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-mpc5121.c (10328B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Real-time clock driver for MPC5121
      4 *
      5 * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
      6 * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
      7 * Copyright 2011, Dmitry Eremin-Solenikov
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/module.h>
     12#include <linux/rtc.h>
     13#include <linux/of.h>
     14#include <linux/of_address.h>
     15#include <linux/of_device.h>
     16#include <linux/of_irq.h>
     17#include <linux/of_platform.h>
     18#include <linux/io.h>
     19#include <linux/slab.h>
     20
     21struct mpc5121_rtc_regs {
     22	u8 set_time;		/* RTC + 0x00 */
     23	u8 hour_set;		/* RTC + 0x01 */
     24	u8 minute_set;		/* RTC + 0x02 */
     25	u8 second_set;		/* RTC + 0x03 */
     26
     27	u8 set_date;		/* RTC + 0x04 */
     28	u8 month_set;		/* RTC + 0x05 */
     29	u8 weekday_set;		/* RTC + 0x06 */
     30	u8 date_set;		/* RTC + 0x07 */
     31
     32	u8 write_sw;		/* RTC + 0x08 */
     33	u8 sw_set;		/* RTC + 0x09 */
     34	u16 year_set;		/* RTC + 0x0a */
     35
     36	u8 alm_enable;		/* RTC + 0x0c */
     37	u8 alm_hour_set;	/* RTC + 0x0d */
     38	u8 alm_min_set;		/* RTC + 0x0e */
     39	u8 int_enable;		/* RTC + 0x0f */
     40
     41	u8 reserved1;
     42	u8 hour;		/* RTC + 0x11 */
     43	u8 minute;		/* RTC + 0x12 */
     44	u8 second;		/* RTC + 0x13 */
     45
     46	u8 month;		/* RTC + 0x14 */
     47	u8 wday_mday;		/* RTC + 0x15 */
     48	u16 year;		/* RTC + 0x16 */
     49
     50	u8 int_alm;		/* RTC + 0x18 */
     51	u8 int_sw;		/* RTC + 0x19 */
     52	u8 alm_status;		/* RTC + 0x1a */
     53	u8 sw_minute;		/* RTC + 0x1b */
     54
     55	u8 bus_error_1;		/* RTC + 0x1c */
     56	u8 int_day;		/* RTC + 0x1d */
     57	u8 int_min;		/* RTC + 0x1e */
     58	u8 int_sec;		/* RTC + 0x1f */
     59
     60	/*
     61	 * target_time:
     62	 *	intended to be used for hibernation but hibernation
     63	 *	does not work on silicon rev 1.5 so use it for non-volatile
     64	 *	storage of offset between the actual_time register and linux
     65	 *	time
     66	 */
     67	u32 target_time;	/* RTC + 0x20 */
     68	/*
     69	 * actual_time:
     70	 *	readonly time since VBAT_RTC was last connected
     71	 */
     72	u32 actual_time;	/* RTC + 0x24 */
     73	u32 keep_alive;		/* RTC + 0x28 */
     74};
     75
     76struct mpc5121_rtc_data {
     77	unsigned irq;
     78	unsigned irq_periodic;
     79	struct mpc5121_rtc_regs __iomem *regs;
     80	struct rtc_device *rtc;
     81	struct rtc_wkalrm wkalarm;
     82};
     83
     84/*
     85 * Update second/minute/hour registers.
     86 *
     87 * This is just so alarm will work.
     88 */
     89static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
     90				   struct rtc_time *tm)
     91{
     92	out_8(&regs->second_set, tm->tm_sec);
     93	out_8(&regs->minute_set, tm->tm_min);
     94	out_8(&regs->hour_set, tm->tm_hour);
     95
     96	/* set time sequence */
     97	out_8(&regs->set_time, 0x1);
     98	out_8(&regs->set_time, 0x3);
     99	out_8(&regs->set_time, 0x1);
    100	out_8(&regs->set_time, 0x0);
    101}
    102
    103static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
    104{
    105	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    106	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    107	unsigned long now;
    108
    109	/*
    110	 * linux time is actual_time plus the offset saved in target_time
    111	 */
    112	now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
    113
    114	rtc_time64_to_tm(now, tm);
    115
    116	/*
    117	 * update second minute hour registers
    118	 * so alarms will work
    119	 */
    120	mpc5121_rtc_update_smh(regs, tm);
    121
    122	return 0;
    123}
    124
    125static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
    126{
    127	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    128	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    129	unsigned long now;
    130
    131	/*
    132	 * The actual_time register is read only so we write the offset
    133	 * between it and linux time to the target_time register.
    134	 */
    135	now = rtc_tm_to_time64(tm);
    136	out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
    137
    138	/*
    139	 * update second minute hour registers
    140	 * so alarms will work
    141	 */
    142	mpc5121_rtc_update_smh(regs, tm);
    143
    144	return 0;
    145}
    146
    147static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm)
    148{
    149	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    150	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    151	int tmp;
    152
    153	tm->tm_sec = in_8(&regs->second);
    154	tm->tm_min = in_8(&regs->minute);
    155
    156	/* 12 hour format? */
    157	if (in_8(&regs->hour) & 0x20)
    158		tm->tm_hour = (in_8(&regs->hour) >> 1) +
    159			(in_8(&regs->hour) & 1 ? 12 : 0);
    160	else
    161		tm->tm_hour = in_8(&regs->hour);
    162
    163	tmp = in_8(&regs->wday_mday);
    164	tm->tm_mday = tmp & 0x1f;
    165	tm->tm_mon = in_8(&regs->month) - 1;
    166	tm->tm_year = in_be16(&regs->year) - 1900;
    167	tm->tm_wday = (tmp >> 5) % 7;
    168	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
    169	tm->tm_isdst = 0;
    170
    171	return 0;
    172}
    173
    174static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm)
    175{
    176	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    177	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    178
    179	mpc5121_rtc_update_smh(regs, tm);
    180
    181	/* date */
    182	out_8(&regs->month_set, tm->tm_mon + 1);
    183	out_8(&regs->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
    184	out_8(&regs->date_set, tm->tm_mday);
    185	out_be16(&regs->year_set, tm->tm_year + 1900);
    186
    187	/* set date sequence */
    188	out_8(&regs->set_date, 0x1);
    189	out_8(&regs->set_date, 0x3);
    190	out_8(&regs->set_date, 0x1);
    191	out_8(&regs->set_date, 0x0);
    192
    193	return 0;
    194}
    195
    196static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    197{
    198	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    199	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    200
    201	*alarm = rtc->wkalarm;
    202
    203	alarm->pending = in_8(&regs->alm_status);
    204
    205	return 0;
    206}
    207
    208static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    209{
    210	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    211	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    212
    213	alarm->time.tm_mday = -1;
    214	alarm->time.tm_mon = -1;
    215	alarm->time.tm_year = -1;
    216
    217	out_8(&regs->alm_min_set, alarm->time.tm_min);
    218	out_8(&regs->alm_hour_set, alarm->time.tm_hour);
    219
    220	out_8(&regs->alm_enable, alarm->enabled);
    221
    222	rtc->wkalarm = *alarm;
    223	return 0;
    224}
    225
    226static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
    227{
    228	struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
    229	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    230
    231	if (in_8(&regs->int_alm)) {
    232		/* acknowledge and clear status */
    233		out_8(&regs->int_alm, 1);
    234		out_8(&regs->alm_status, 1);
    235
    236		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
    237		return IRQ_HANDLED;
    238	}
    239
    240	return IRQ_NONE;
    241}
    242
    243static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
    244{
    245	struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
    246	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    247
    248	if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
    249		/* acknowledge */
    250		out_8(&regs->int_sec, 1);
    251
    252		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
    253		return IRQ_HANDLED;
    254	}
    255
    256	return IRQ_NONE;
    257}
    258
    259static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
    260					unsigned int enabled)
    261{
    262	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
    263	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    264	int val;
    265
    266	if (enabled)
    267		val = 1;
    268	else
    269		val = 0;
    270
    271	out_8(&regs->alm_enable, val);
    272	rtc->wkalarm.enabled = val;
    273
    274	return 0;
    275}
    276
    277static const struct rtc_class_ops mpc5121_rtc_ops = {
    278	.read_time = mpc5121_rtc_read_time,
    279	.set_time = mpc5121_rtc_set_time,
    280	.read_alarm = mpc5121_rtc_read_alarm,
    281	.set_alarm = mpc5121_rtc_set_alarm,
    282	.alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
    283};
    284
    285static const struct rtc_class_ops mpc5200_rtc_ops = {
    286	.read_time = mpc5200_rtc_read_time,
    287	.set_time = mpc5200_rtc_set_time,
    288	.read_alarm = mpc5121_rtc_read_alarm,
    289	.set_alarm = mpc5121_rtc_set_alarm,
    290	.alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
    291};
    292
    293static int mpc5121_rtc_probe(struct platform_device *op)
    294{
    295	struct mpc5121_rtc_data *rtc;
    296	int err = 0;
    297
    298	rtc = devm_kzalloc(&op->dev, sizeof(*rtc), GFP_KERNEL);
    299	if (!rtc)
    300		return -ENOMEM;
    301
    302	rtc->regs = devm_platform_ioremap_resource(op, 0);
    303	if (IS_ERR(rtc->regs)) {
    304		dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
    305		return PTR_ERR(rtc->regs);
    306	}
    307
    308	device_init_wakeup(&op->dev, 1);
    309
    310	platform_set_drvdata(op, rtc);
    311
    312	rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
    313	err = devm_request_irq(&op->dev, rtc->irq, mpc5121_rtc_handler, 0,
    314			       "mpc5121-rtc", &op->dev);
    315	if (err) {
    316		dev_err(&op->dev, "%s: could not request irq: %i\n",
    317							__func__, rtc->irq);
    318		goto out_dispose;
    319	}
    320
    321	rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
    322	err = devm_request_irq(&op->dev, rtc->irq_periodic,
    323			       mpc5121_rtc_handler_upd, 0, "mpc5121-rtc_upd",
    324			       &op->dev);
    325	if (err) {
    326		dev_err(&op->dev, "%s: could not request irq: %i\n",
    327						__func__, rtc->irq_periodic);
    328		goto out_dispose2;
    329	}
    330
    331	rtc->rtc = devm_rtc_allocate_device(&op->dev);
    332	if (IS_ERR(rtc->rtc)) {
    333		err = PTR_ERR(rtc->rtc);
    334		goto out_dispose2;
    335	}
    336
    337	rtc->rtc->ops = &mpc5200_rtc_ops;
    338	set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtc->features);
    339	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc->features);
    340	rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;
    341	rtc->rtc->range_max = 65733206399ULL; /* 4052-12-31 23:59:59 */
    342
    343	if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) {
    344		u32 ka;
    345		ka = in_be32(&rtc->regs->keep_alive);
    346		if (ka & 0x02) {
    347			dev_warn(&op->dev,
    348				"mpc5121-rtc: Battery or oscillator failure!\n");
    349			out_be32(&rtc->regs->keep_alive, ka);
    350		}
    351		rtc->rtc->ops = &mpc5121_rtc_ops;
    352		/*
    353		 * This is a limitation of the driver that abuses the target
    354		 * time register, the actual maximum year for the mpc5121 is
    355		 * also 4052.
    356		 */
    357		rtc->rtc->range_min = 0;
    358		rtc->rtc->range_max = U32_MAX;
    359	}
    360
    361	err = devm_rtc_register_device(rtc->rtc);
    362	if (err)
    363		goto out_dispose2;
    364
    365	return 0;
    366
    367out_dispose2:
    368	irq_dispose_mapping(rtc->irq_periodic);
    369out_dispose:
    370	irq_dispose_mapping(rtc->irq);
    371
    372	return err;
    373}
    374
    375static int mpc5121_rtc_remove(struct platform_device *op)
    376{
    377	struct mpc5121_rtc_data *rtc = platform_get_drvdata(op);
    378	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
    379
    380	/* disable interrupt, so there are no nasty surprises */
    381	out_8(&regs->alm_enable, 0);
    382	out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
    383
    384	irq_dispose_mapping(rtc->irq);
    385	irq_dispose_mapping(rtc->irq_periodic);
    386
    387	return 0;
    388}
    389
    390#ifdef CONFIG_OF
    391static const struct of_device_id mpc5121_rtc_match[] = {
    392	{ .compatible = "fsl,mpc5121-rtc", },
    393	{ .compatible = "fsl,mpc5200-rtc", },
    394	{},
    395};
    396MODULE_DEVICE_TABLE(of, mpc5121_rtc_match);
    397#endif
    398
    399static struct platform_driver mpc5121_rtc_driver = {
    400	.driver = {
    401		.name = "mpc5121-rtc",
    402		.of_match_table = of_match_ptr(mpc5121_rtc_match),
    403	},
    404	.probe = mpc5121_rtc_probe,
    405	.remove = mpc5121_rtc_remove,
    406};
    407
    408module_platform_driver(mpc5121_rtc_driver);
    409
    410MODULE_LICENSE("GPL");
    411MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");