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

time.c (8418B)


      1/*
      2 * linux/arch/m68k/atari/time.c
      3 *
      4 * Atari time and real time clock stuff
      5 *
      6 * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
      7 *
      8 * This file is subject to the terms and conditions of the GNU General Public
      9 * License.  See the file COPYING in the main directory of this archive
     10 * for more details.
     11 */
     12
     13#include <linux/types.h>
     14#include <linux/mc146818rtc.h>
     15#include <linux/interrupt.h>
     16#include <linux/init.h>
     17#include <linux/rtc.h>
     18#include <linux/bcd.h>
     19#include <linux/clocksource.h>
     20#include <linux/delay.h>
     21#include <linux/export.h>
     22
     23#include <asm/atariints.h>
     24#include <asm/machdep.h>
     25
     26DEFINE_SPINLOCK(rtc_lock);
     27EXPORT_SYMBOL_GPL(rtc_lock);
     28
     29static u64 atari_read_clk(struct clocksource *cs);
     30
     31static struct clocksource atari_clk = {
     32	.name   = "mfp",
     33	.rating = 100,
     34	.read   = atari_read_clk,
     35	.mask   = CLOCKSOURCE_MASK(32),
     36	.flags  = CLOCK_SOURCE_IS_CONTINUOUS,
     37};
     38
     39static u32 clk_total;
     40static u8 last_timer_count;
     41
     42static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
     43{
     44	unsigned long flags;
     45
     46	local_irq_save(flags);
     47	do {
     48		last_timer_count = st_mfp.tim_dt_c;
     49	} while (last_timer_count == 1);
     50	clk_total += INT_TICKS;
     51	legacy_timer_tick(1);
     52	timer_heartbeat();
     53	local_irq_restore(flags);
     54
     55	return IRQ_HANDLED;
     56}
     57
     58void __init
     59atari_sched_init(void)
     60{
     61    /* set Timer C data Register */
     62    st_mfp.tim_dt_c = INT_TICKS;
     63    /* start timer C, div = 1:100 */
     64    st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
     65    /* install interrupt service routine for MFP Timer C */
     66    if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, IRQF_TIMER, "timer",
     67                    NULL))
     68	pr_err("Couldn't register timer interrupt\n");
     69
     70    clocksource_register_hz(&atari_clk, INT_CLK);
     71}
     72
     73/* ++andreas: gettimeoffset fixed to check for pending interrupt */
     74
     75static u64 atari_read_clk(struct clocksource *cs)
     76{
     77	unsigned long flags;
     78	u8 count;
     79	u32 ticks;
     80
     81	local_irq_save(flags);
     82	/* Ensure that the count is monotonically decreasing, even though
     83	 * the result may briefly stop changing after counter wrap-around.
     84	 */
     85	count = min(st_mfp.tim_dt_c, last_timer_count);
     86	last_timer_count = count;
     87
     88	ticks = INT_TICKS - count;
     89	ticks += clk_total;
     90	local_irq_restore(flags);
     91
     92	return ticks;
     93}
     94
     95
     96static void mste_read(struct MSTE_RTC *val)
     97{
     98#define COPY(v) val->v=(mste_rtc.v & 0xf)
     99	do {
    100		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
    101		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
    102		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
    103		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
    104		COPY(year_tens) ;
    105	/* prevent from reading the clock while it changed */
    106	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
    107#undef COPY
    108}
    109
    110static void mste_write(struct MSTE_RTC *val)
    111{
    112#define COPY(v) mste_rtc.v=val->v
    113	do {
    114		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
    115		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
    116		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
    117		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
    118		COPY(year_tens) ;
    119	/* prevent from writing the clock while it changed */
    120	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
    121#undef COPY
    122}
    123
    124#define	RTC_READ(reg)				\
    125    ({	unsigned char	__val;			\
    126		(void) atari_writeb(reg,&tt_rtc.regsel);	\
    127		__val = tt_rtc.data;		\
    128		__val;				\
    129	})
    130
    131#define	RTC_WRITE(reg,val)			\
    132    do {					\
    133		atari_writeb(reg,&tt_rtc.regsel);	\
    134		tt_rtc.data = (val);		\
    135	} while(0)
    136
    137
    138#define HWCLK_POLL_INTERVAL	5
    139
    140int atari_mste_hwclk( int op, struct rtc_time *t )
    141{
    142    int hour, year;
    143    int hr24=0;
    144    struct MSTE_RTC val;
    145
    146    mste_rtc.mode=(mste_rtc.mode | 1);
    147    hr24=mste_rtc.mon_tens & 1;
    148    mste_rtc.mode=(mste_rtc.mode & ~1);
    149
    150    if (op) {
    151        /* write: prepare values */
    152
    153        val.sec_ones = t->tm_sec % 10;
    154        val.sec_tens = t->tm_sec / 10;
    155        val.min_ones = t->tm_min % 10;
    156        val.min_tens = t->tm_min / 10;
    157        hour = t->tm_hour;
    158        if (!hr24) {
    159	    if (hour > 11)
    160		hour += 20 - 12;
    161	    if (hour == 0 || hour == 20)
    162		hour += 12;
    163        }
    164        val.hr_ones = hour % 10;
    165        val.hr_tens = hour / 10;
    166        val.day_ones = t->tm_mday % 10;
    167        val.day_tens = t->tm_mday / 10;
    168        val.mon_ones = (t->tm_mon+1) % 10;
    169        val.mon_tens = (t->tm_mon+1) / 10;
    170        year = t->tm_year - 80;
    171        val.year_ones = year % 10;
    172        val.year_tens = year / 10;
    173        val.weekday = t->tm_wday;
    174        mste_write(&val);
    175        mste_rtc.mode=(mste_rtc.mode | 1);
    176        val.year_ones = (year % 4);	/* leap year register */
    177        mste_rtc.mode=(mste_rtc.mode & ~1);
    178    }
    179    else {
    180        mste_read(&val);
    181        t->tm_sec = val.sec_ones + val.sec_tens * 10;
    182        t->tm_min = val.min_ones + val.min_tens * 10;
    183        hour = val.hr_ones + val.hr_tens * 10;
    184	if (!hr24) {
    185	    if (hour == 12 || hour == 12 + 20)
    186		hour -= 12;
    187	    if (hour >= 20)
    188                hour += 12 - 20;
    189        }
    190	t->tm_hour = hour;
    191	t->tm_mday = val.day_ones + val.day_tens * 10;
    192        t->tm_mon  = val.mon_ones + val.mon_tens * 10 - 1;
    193        t->tm_year = val.year_ones + val.year_tens * 10 + 80;
    194        t->tm_wday = val.weekday;
    195    }
    196    return 0;
    197}
    198
    199int atari_tt_hwclk( int op, struct rtc_time *t )
    200{
    201    int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
    202    unsigned long	flags;
    203    unsigned char	ctrl;
    204    int pm = 0;
    205
    206    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
    207                                   * independent from the UIP */
    208
    209    if (op) {
    210        /* write: prepare values */
    211
    212        sec  = t->tm_sec;
    213        min  = t->tm_min;
    214        hour = t->tm_hour;
    215        day  = t->tm_mday;
    216        mon  = t->tm_mon + 1;
    217        year = t->tm_year - atari_rtc_year_offset;
    218        wday = t->tm_wday + (t->tm_wday >= 0);
    219
    220        if (!(ctrl & RTC_24H)) {
    221	    if (hour > 11) {
    222		pm = 0x80;
    223		if (hour != 12)
    224		    hour -= 12;
    225	    }
    226	    else if (hour == 0)
    227		hour = 12;
    228        }
    229
    230        if (!(ctrl & RTC_DM_BINARY)) {
    231	    sec = bin2bcd(sec);
    232	    min = bin2bcd(min);
    233	    hour = bin2bcd(hour);
    234	    day = bin2bcd(day);
    235	    mon = bin2bcd(mon);
    236	    year = bin2bcd(year);
    237	    if (wday >= 0)
    238		wday = bin2bcd(wday);
    239        }
    240    }
    241
    242    /* Reading/writing the clock registers is a bit critical due to
    243     * the regular update cycle of the RTC. While an update is in
    244     * progress, registers 0..9 shouldn't be touched.
    245     * The problem is solved like that: If an update is currently in
    246     * progress (the UIP bit is set), the process sleeps for a while
    247     * (50ms). This really should be enough, since the update cycle
    248     * normally needs 2 ms.
    249     * If the UIP bit reads as 0, we have at least 244 usecs until the
    250     * update starts. This should be enough... But to be sure,
    251     * additionally the RTC_SET bit is set to prevent an update cycle.
    252     */
    253
    254    while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
    255	if (in_atomic() || irqs_disabled())
    256	    mdelay(1);
    257	else
    258	    schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
    259    }
    260
    261    local_irq_save(flags);
    262    RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
    263    if (!op) {
    264        sec  = RTC_READ( RTC_SECONDS );
    265        min  = RTC_READ( RTC_MINUTES );
    266        hour = RTC_READ( RTC_HOURS );
    267        day  = RTC_READ( RTC_DAY_OF_MONTH );
    268        mon  = RTC_READ( RTC_MONTH );
    269        year = RTC_READ( RTC_YEAR );
    270        wday = RTC_READ( RTC_DAY_OF_WEEK );
    271    }
    272    else {
    273        RTC_WRITE( RTC_SECONDS, sec );
    274        RTC_WRITE( RTC_MINUTES, min );
    275        RTC_WRITE( RTC_HOURS, hour + pm);
    276        RTC_WRITE( RTC_DAY_OF_MONTH, day );
    277        RTC_WRITE( RTC_MONTH, mon );
    278        RTC_WRITE( RTC_YEAR, year );
    279        if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
    280    }
    281    RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
    282    local_irq_restore(flags);
    283
    284    if (!op) {
    285        /* read: adjust values */
    286
    287        if (hour & 0x80) {
    288	    hour &= ~0x80;
    289	    pm = 1;
    290	}
    291
    292	if (!(ctrl & RTC_DM_BINARY)) {
    293	    sec = bcd2bin(sec);
    294	    min = bcd2bin(min);
    295	    hour = bcd2bin(hour);
    296	    day = bcd2bin(day);
    297	    mon = bcd2bin(mon);
    298	    year = bcd2bin(year);
    299	    wday = bcd2bin(wday);
    300        }
    301
    302        if (!(ctrl & RTC_24H)) {
    303	    if (!pm && hour == 12)
    304		hour = 0;
    305	    else if (pm && hour != 12)
    306		hour += 12;
    307        }
    308
    309        t->tm_sec  = sec;
    310        t->tm_min  = min;
    311        t->tm_hour = hour;
    312        t->tm_mday = day;
    313        t->tm_mon  = mon - 1;
    314        t->tm_year = year + atari_rtc_year_offset;
    315        t->tm_wday = wday - 1;
    316    }
    317
    318    return( 0 );
    319}