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-lpc32xx.c (8785B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2010 NXP Semiconductors
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/module.h>
      8#include <linux/init.h>
      9#include <linux/platform_device.h>
     10#include <linux/spinlock.h>
     11#include <linux/rtc.h>
     12#include <linux/slab.h>
     13#include <linux/io.h>
     14#include <linux/of.h>
     15
     16/*
     17 * Clock and Power control register offsets
     18 */
     19#define LPC32XX_RTC_UCOUNT		0x00
     20#define LPC32XX_RTC_DCOUNT		0x04
     21#define LPC32XX_RTC_MATCH0		0x08
     22#define LPC32XX_RTC_MATCH1		0x0C
     23#define LPC32XX_RTC_CTRL		0x10
     24#define LPC32XX_RTC_INTSTAT		0x14
     25#define LPC32XX_RTC_KEY			0x18
     26#define LPC32XX_RTC_SRAM		0x80
     27
     28#define LPC32XX_RTC_CTRL_MATCH0		(1 << 0)
     29#define LPC32XX_RTC_CTRL_MATCH1		(1 << 1)
     30#define LPC32XX_RTC_CTRL_ONSW_MATCH0	(1 << 2)
     31#define LPC32XX_RTC_CTRL_ONSW_MATCH1	(1 << 3)
     32#define LPC32XX_RTC_CTRL_SW_RESET	(1 << 4)
     33#define LPC32XX_RTC_CTRL_CNTR_DIS	(1 << 6)
     34#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI	(1 << 7)
     35
     36#define LPC32XX_RTC_INTSTAT_MATCH0	(1 << 0)
     37#define LPC32XX_RTC_INTSTAT_MATCH1	(1 << 1)
     38#define LPC32XX_RTC_INTSTAT_ONSW	(1 << 2)
     39
     40#define LPC32XX_RTC_KEY_ONSW_LOADVAL	0xB5C13F27
     41
     42#define rtc_readl(dev, reg) \
     43	__raw_readl((dev)->rtc_base + (reg))
     44#define rtc_writel(dev, reg, val) \
     45	__raw_writel((val), (dev)->rtc_base + (reg))
     46
     47struct lpc32xx_rtc {
     48	void __iomem *rtc_base;
     49	int irq;
     50	unsigned char alarm_enabled;
     51	struct rtc_device *rtc;
     52	spinlock_t lock;
     53};
     54
     55static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time)
     56{
     57	unsigned long elapsed_sec;
     58	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
     59
     60	elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT);
     61	rtc_time64_to_tm(elapsed_sec, time);
     62
     63	return 0;
     64}
     65
     66static int lpc32xx_rtc_set_time(struct device *dev, struct rtc_time *time)
     67{
     68	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
     69	u32 secs = rtc_tm_to_time64(time);
     70	u32 tmp;
     71
     72	spin_lock_irq(&rtc->lock);
     73
     74	/* RTC must be disabled during count update */
     75	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
     76	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS);
     77	rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs);
     78	rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs);
     79	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS);
     80
     81	spin_unlock_irq(&rtc->lock);
     82
     83	return 0;
     84}
     85
     86static int lpc32xx_rtc_read_alarm(struct device *dev,
     87	struct rtc_wkalrm *wkalrm)
     88{
     89	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
     90
     91	rtc_time64_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time);
     92	wkalrm->enabled = rtc->alarm_enabled;
     93	wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) &
     94		LPC32XX_RTC_INTSTAT_MATCH0);
     95
     96	return rtc_valid_tm(&wkalrm->time);
     97}
     98
     99static int lpc32xx_rtc_set_alarm(struct device *dev,
    100	struct rtc_wkalrm *wkalrm)
    101{
    102	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
    103	unsigned long alarmsecs;
    104	u32 tmp;
    105
    106	alarmsecs = rtc_tm_to_time64(&wkalrm->time);
    107
    108	spin_lock_irq(&rtc->lock);
    109
    110	/* Disable alarm during update */
    111	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
    112	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0);
    113
    114	rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs);
    115
    116	rtc->alarm_enabled = wkalrm->enabled;
    117	if (wkalrm->enabled) {
    118		rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
    119			   LPC32XX_RTC_INTSTAT_MATCH0);
    120		rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp |
    121			   LPC32XX_RTC_CTRL_MATCH0);
    122	}
    123
    124	spin_unlock_irq(&rtc->lock);
    125
    126	return 0;
    127}
    128
    129static int lpc32xx_rtc_alarm_irq_enable(struct device *dev,
    130	unsigned int enabled)
    131{
    132	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
    133	u32 tmp;
    134
    135	spin_lock_irq(&rtc->lock);
    136	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
    137
    138	if (enabled) {
    139		rtc->alarm_enabled = 1;
    140		tmp |= LPC32XX_RTC_CTRL_MATCH0;
    141	} else {
    142		rtc->alarm_enabled = 0;
    143		tmp &= ~LPC32XX_RTC_CTRL_MATCH0;
    144	}
    145
    146	rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
    147	spin_unlock_irq(&rtc->lock);
    148
    149	return 0;
    150}
    151
    152static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev)
    153{
    154	struct lpc32xx_rtc *rtc = dev;
    155
    156	spin_lock(&rtc->lock);
    157
    158	/* Disable alarm interrupt */
    159	rtc_writel(rtc, LPC32XX_RTC_CTRL,
    160		rtc_readl(rtc, LPC32XX_RTC_CTRL) &
    161			  ~LPC32XX_RTC_CTRL_MATCH0);
    162	rtc->alarm_enabled = 0;
    163
    164	/*
    165	 * Write a large value to the match value so the RTC won't
    166	 * keep firing the match status
    167	 */
    168	rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
    169	rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0);
    170
    171	spin_unlock(&rtc->lock);
    172
    173	rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
    174
    175	return IRQ_HANDLED;
    176}
    177
    178static const struct rtc_class_ops lpc32xx_rtc_ops = {
    179	.read_time		= lpc32xx_rtc_read_time,
    180	.set_time		= lpc32xx_rtc_set_time,
    181	.read_alarm		= lpc32xx_rtc_read_alarm,
    182	.set_alarm		= lpc32xx_rtc_set_alarm,
    183	.alarm_irq_enable	= lpc32xx_rtc_alarm_irq_enable,
    184};
    185
    186static int lpc32xx_rtc_probe(struct platform_device *pdev)
    187{
    188	struct lpc32xx_rtc *rtc;
    189	int err;
    190	u32 tmp;
    191
    192	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
    193	if (unlikely(!rtc))
    194		return -ENOMEM;
    195
    196	rtc->rtc_base = devm_platform_ioremap_resource(pdev, 0);
    197	if (IS_ERR(rtc->rtc_base))
    198		return PTR_ERR(rtc->rtc_base);
    199
    200	spin_lock_init(&rtc->lock);
    201
    202	/*
    203	 * The RTC is on a separate power domain and can keep it's state
    204	 * across a chip power cycle. If the RTC has never been previously
    205	 * setup, then set it up now for the first time.
    206	 */
    207	tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
    208	if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {
    209		tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |
    210			LPC32XX_RTC_CTRL_CNTR_DIS |
    211			LPC32XX_RTC_CTRL_MATCH0 |
    212			LPC32XX_RTC_CTRL_MATCH1 |
    213			LPC32XX_RTC_CTRL_ONSW_MATCH0 |
    214			LPC32XX_RTC_CTRL_ONSW_MATCH1 |
    215			LPC32XX_RTC_CTRL_ONSW_FORCE_HI);
    216		rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
    217
    218		/* Clear latched interrupt states */
    219		rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
    220		rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
    221			   LPC32XX_RTC_INTSTAT_MATCH0 |
    222			   LPC32XX_RTC_INTSTAT_MATCH1 |
    223			   LPC32XX_RTC_INTSTAT_ONSW);
    224
    225		/* Write key value to RTC so it won't reload on reset */
    226		rtc_writel(rtc, LPC32XX_RTC_KEY,
    227			   LPC32XX_RTC_KEY_ONSW_LOADVAL);
    228	} else {
    229		rtc_writel(rtc, LPC32XX_RTC_CTRL,
    230			   tmp & ~LPC32XX_RTC_CTRL_MATCH0);
    231	}
    232
    233	platform_set_drvdata(pdev, rtc);
    234
    235	rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
    236	if (IS_ERR(rtc->rtc))
    237		return PTR_ERR(rtc->rtc);
    238
    239	rtc->rtc->ops = &lpc32xx_rtc_ops;
    240	rtc->rtc->range_max = U32_MAX;
    241
    242	err = devm_rtc_register_device(rtc->rtc);
    243	if (err)
    244		return err;
    245
    246	/*
    247	 * IRQ is enabled after device registration in case alarm IRQ
    248	 * is pending upon suspend exit.
    249	 */
    250	rtc->irq = platform_get_irq(pdev, 0);
    251	if (rtc->irq < 0) {
    252		dev_warn(&pdev->dev, "Can't get interrupt resource\n");
    253	} else {
    254		if (devm_request_irq(&pdev->dev, rtc->irq,
    255				     lpc32xx_rtc_alarm_interrupt,
    256				     0, pdev->name, rtc) < 0) {
    257			dev_warn(&pdev->dev, "Can't request interrupt.\n");
    258			rtc->irq = -1;
    259		} else {
    260			device_init_wakeup(&pdev->dev, 1);
    261		}
    262	}
    263
    264	return 0;
    265}
    266
    267#ifdef CONFIG_PM
    268static int lpc32xx_rtc_suspend(struct device *dev)
    269{
    270	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
    271
    272	if (rtc->irq >= 0) {
    273		if (device_may_wakeup(dev))
    274			enable_irq_wake(rtc->irq);
    275		else
    276			disable_irq_wake(rtc->irq);
    277	}
    278
    279	return 0;
    280}
    281
    282static int lpc32xx_rtc_resume(struct device *dev)
    283{
    284	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
    285
    286	if (rtc->irq >= 0 && device_may_wakeup(dev))
    287		disable_irq_wake(rtc->irq);
    288
    289	return 0;
    290}
    291
    292/* Unconditionally disable the alarm */
    293static int lpc32xx_rtc_freeze(struct device *dev)
    294{
    295	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
    296
    297	spin_lock_irq(&rtc->lock);
    298
    299	rtc_writel(rtc, LPC32XX_RTC_CTRL,
    300		rtc_readl(rtc, LPC32XX_RTC_CTRL) &
    301			  ~LPC32XX_RTC_CTRL_MATCH0);
    302
    303	spin_unlock_irq(&rtc->lock);
    304
    305	return 0;
    306}
    307
    308static int lpc32xx_rtc_thaw(struct device *dev)
    309{
    310	struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
    311
    312	if (rtc->alarm_enabled) {
    313		spin_lock_irq(&rtc->lock);
    314
    315		rtc_writel(rtc, LPC32XX_RTC_CTRL,
    316			   rtc_readl(rtc, LPC32XX_RTC_CTRL) |
    317			   LPC32XX_RTC_CTRL_MATCH0);
    318
    319		spin_unlock_irq(&rtc->lock);
    320	}
    321
    322	return 0;
    323}
    324
    325static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
    326	.suspend = lpc32xx_rtc_suspend,
    327	.resume = lpc32xx_rtc_resume,
    328	.freeze = lpc32xx_rtc_freeze,
    329	.thaw = lpc32xx_rtc_thaw,
    330	.restore = lpc32xx_rtc_resume
    331};
    332
    333#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
    334#else
    335#define LPC32XX_RTC_PM_OPS NULL
    336#endif
    337
    338#ifdef CONFIG_OF
    339static const struct of_device_id lpc32xx_rtc_match[] = {
    340	{ .compatible = "nxp,lpc3220-rtc" },
    341	{ }
    342};
    343MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
    344#endif
    345
    346static struct platform_driver lpc32xx_rtc_driver = {
    347	.probe		= lpc32xx_rtc_probe,
    348	.driver = {
    349		.name	= "rtc-lpc32xx",
    350		.pm	= LPC32XX_RTC_PM_OPS,
    351		.of_match_table = of_match_ptr(lpc32xx_rtc_match),
    352	},
    353};
    354
    355module_platform_driver(lpc32xx_rtc_driver);
    356
    357MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
    358MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
    359MODULE_LICENSE("GPL");
    360MODULE_ALIAS("platform:rtc-lpc32xx");