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_m41t81.c (6711B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2000, 2001 Broadcom Corporation
      4 *
      5 * Copyright (C) 2002 MontaVista Software Inc.
      6 * Author: jsun@mvista.com or jsun@junsun.net
      7 */
      8#include <linux/bcd.h>
      9#include <linux/types.h>
     10#include <linux/time.h>
     11
     12#include <asm/time.h>
     13#include <asm/addrspace.h>
     14#include <asm/io.h>
     15
     16#include <asm/sibyte/sb1250.h>
     17#include <asm/sibyte/sb1250_regs.h>
     18#include <asm/sibyte/sb1250_smbus.h>
     19
     20
     21/* M41T81 definitions */
     22
     23/*
     24 * Register bits
     25 */
     26
     27#define M41T81REG_SC_ST		0x80		/* stop bit */
     28#define M41T81REG_HR_CB		0x40		/* century bit */
     29#define M41T81REG_HR_CEB	0x80		/* century enable bit */
     30#define M41T81REG_CTL_S		0x20		/* sign bit */
     31#define M41T81REG_CTL_FT	0x40		/* frequency test bit */
     32#define M41T81REG_CTL_OUT	0x80		/* output level */
     33#define M41T81REG_WD_RB0	0x01		/* watchdog resolution bit 0 */
     34#define M41T81REG_WD_RB1	0x02		/* watchdog resolution bit 1 */
     35#define M41T81REG_WD_BMB0	0x04		/* watchdog multiplier bit 0 */
     36#define M41T81REG_WD_BMB1	0x08		/* watchdog multiplier bit 1 */
     37#define M41T81REG_WD_BMB2	0x10		/* watchdog multiplier bit 2 */
     38#define M41T81REG_WD_BMB3	0x20		/* watchdog multiplier bit 3 */
     39#define M41T81REG_WD_BMB4	0x40		/* watchdog multiplier bit 4 */
     40#define M41T81REG_AMO_ABE	0x20		/* alarm in "battery back-up mode" enable bit */
     41#define M41T81REG_AMO_SQWE	0x40		/* square wave enable */
     42#define M41T81REG_AMO_AFE	0x80		/* alarm flag enable flag */
     43#define M41T81REG_ADT_RPT5	0x40		/* alarm repeat mode bit 5 */
     44#define M41T81REG_ADT_RPT4	0x80		/* alarm repeat mode bit 4 */
     45#define M41T81REG_AHR_RPT3	0x80		/* alarm repeat mode bit 3 */
     46#define M41T81REG_AHR_HT	0x40		/* halt update bit */
     47#define M41T81REG_AMN_RPT2	0x80		/* alarm repeat mode bit 2 */
     48#define M41T81REG_ASC_RPT1	0x80		/* alarm repeat mode bit 1 */
     49#define M41T81REG_FLG_AF	0x40		/* alarm flag (read only) */
     50#define M41T81REG_FLG_WDF	0x80		/* watchdog flag (read only) */
     51#define M41T81REG_SQW_RS0	0x10		/* sqw frequency bit 0 */
     52#define M41T81REG_SQW_RS1	0x20		/* sqw frequency bit 1 */
     53#define M41T81REG_SQW_RS2	0x40		/* sqw frequency bit 2 */
     54#define M41T81REG_SQW_RS3	0x80		/* sqw frequency bit 3 */
     55
     56
     57/*
     58 * Register numbers
     59 */
     60
     61#define M41T81REG_TSC	0x00		/* tenths/hundredths of second */
     62#define M41T81REG_SC	0x01		/* seconds */
     63#define M41T81REG_MN	0x02		/* minute */
     64#define M41T81REG_HR	0x03		/* hour/century */
     65#define M41T81REG_DY	0x04		/* day of week */
     66#define M41T81REG_DT	0x05		/* date of month */
     67#define M41T81REG_MO	0x06		/* month */
     68#define M41T81REG_YR	0x07		/* year */
     69#define M41T81REG_CTL	0x08		/* control */
     70#define M41T81REG_WD	0x09		/* watchdog */
     71#define M41T81REG_AMO	0x0A		/* alarm: month */
     72#define M41T81REG_ADT	0x0B		/* alarm: date */
     73#define M41T81REG_AHR	0x0C		/* alarm: hour */
     74#define M41T81REG_AMN	0x0D		/* alarm: minute */
     75#define M41T81REG_ASC	0x0E		/* alarm: second */
     76#define M41T81REG_FLG	0x0F		/* flags */
     77#define M41T81REG_SQW	0x13		/* square wave register */
     78
     79#define M41T81_CCR_ADDRESS	0x68
     80
     81#define SMB_CSR(reg)	IOADDR(A_SMB_REGISTER(1, reg))
     82
     83static int m41t81_read(uint8_t addr)
     84{
     85	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
     86		;
     87
     88	__raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD));
     89	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR1BYTE,
     90		     SMB_CSR(R_SMB_START));
     91
     92	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
     93		;
     94
     95	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
     96		     SMB_CSR(R_SMB_START));
     97
     98	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
     99		;
    100
    101	if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
    102		/* Clear error bit by writing a 1 */
    103		__raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
    104		return -1;
    105	}
    106
    107	return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff;
    108}
    109
    110static int m41t81_write(uint8_t addr, int b)
    111{
    112	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
    113		;
    114
    115	__raw_writeq(addr & 0xff, SMB_CSR(R_SMB_CMD));
    116	__raw_writeq(b & 0xff, SMB_CSR(R_SMB_DATA));
    117	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
    118		     SMB_CSR(R_SMB_START));
    119
    120	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
    121		;
    122
    123	if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
    124		/* Clear error bit by writing a 1 */
    125		__raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
    126		return -1;
    127	}
    128
    129	/* read the same byte again to make sure it is written */
    130	__raw_writeq(V_SMB_ADDR(M41T81_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
    131		     SMB_CSR(R_SMB_START));
    132
    133	while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
    134		;
    135
    136	return 0;
    137}
    138
    139int m41t81_set_time(time64_t t)
    140{
    141	struct rtc_time tm;
    142	unsigned long flags;
    143
    144	/* Note we don't care about the century */
    145	rtc_time64_to_tm(t, &tm);
    146
    147	/*
    148	 * Note the write order matters as it ensures the correctness.
    149	 * When we write sec, 10th sec is clear.  It is reasonable to
    150	 * believe we should finish writing min within a second.
    151	 */
    152
    153	spin_lock_irqsave(&rtc_lock, flags);
    154	tm.tm_sec = bin2bcd(tm.tm_sec);
    155	m41t81_write(M41T81REG_SC, tm.tm_sec);
    156
    157	tm.tm_min = bin2bcd(tm.tm_min);
    158	m41t81_write(M41T81REG_MN, tm.tm_min);
    159
    160	tm.tm_hour = bin2bcd(tm.tm_hour);
    161	tm.tm_hour = (tm.tm_hour & 0x3f) | (m41t81_read(M41T81REG_HR) & 0xc0);
    162	m41t81_write(M41T81REG_HR, tm.tm_hour);
    163
    164	/* tm_wday starts from 0 to 6 */
    165	if (tm.tm_wday == 0) tm.tm_wday = 7;
    166	tm.tm_wday = bin2bcd(tm.tm_wday);
    167	m41t81_write(M41T81REG_DY, tm.tm_wday);
    168
    169	tm.tm_mday = bin2bcd(tm.tm_mday);
    170	m41t81_write(M41T81REG_DT, tm.tm_mday);
    171
    172	/* tm_mon starts from 0, *ick* */
    173	tm.tm_mon ++;
    174	tm.tm_mon = bin2bcd(tm.tm_mon);
    175	m41t81_write(M41T81REG_MO, tm.tm_mon);
    176
    177	/* we don't do century, everything is beyond 2000 */
    178	tm.tm_year %= 100;
    179	tm.tm_year = bin2bcd(tm.tm_year);
    180	m41t81_write(M41T81REG_YR, tm.tm_year);
    181	spin_unlock_irqrestore(&rtc_lock, flags);
    182
    183	return 0;
    184}
    185
    186time64_t m41t81_get_time(void)
    187{
    188	unsigned int year, mon, day, hour, min, sec;
    189	unsigned long flags;
    190
    191	/*
    192	 * min is valid if two reads of sec are the same.
    193	 */
    194	for (;;) {
    195		spin_lock_irqsave(&rtc_lock, flags);
    196		sec = m41t81_read(M41T81REG_SC);
    197		min = m41t81_read(M41T81REG_MN);
    198		if (sec == m41t81_read(M41T81REG_SC)) break;
    199		spin_unlock_irqrestore(&rtc_lock, flags);
    200	}
    201	hour = m41t81_read(M41T81REG_HR) & 0x3f;
    202	day = m41t81_read(M41T81REG_DT);
    203	mon = m41t81_read(M41T81REG_MO);
    204	year = m41t81_read(M41T81REG_YR);
    205	spin_unlock_irqrestore(&rtc_lock, flags);
    206
    207	sec = bcd2bin(sec);
    208	min = bcd2bin(min);
    209	hour = bcd2bin(hour);
    210	day = bcd2bin(day);
    211	mon = bcd2bin(mon);
    212	year = bcd2bin(year);
    213
    214	year += 2000;
    215
    216	return mktime64(year, mon, day, hour, min, sec);
    217}
    218
    219int m41t81_probe(void)
    220{
    221	unsigned int tmp;
    222
    223	/* enable chip if it is not enabled yet */
    224	tmp = m41t81_read(M41T81REG_SC);
    225	m41t81_write(M41T81REG_SC, tmp & 0x7f);
    226
    227	return m41t81_read(M41T81REG_SC) != -1;
    228}