/*      @(#)clock.h 1.1 92/07/30 SMI      */

/*
 * Copyright (c) 1985 by Sun Microsystems, Inc.
 */

#ifndef _sun4_clock_h
#define _sun4_clock_h

/*
 * There are two types of time of day clock on Sun4 :
 * the Intersil 7170 and the Mostek 48t02.
 */
#define	INTERSIL7170	0
#define	MOSTEK48T02	1

/*
 * Definitions for the Intersil 7170 real-time clock.  This chip
 * is used as the timer chip in addition to being the battery
 * backed up time-of-day device.  This clock is run by UNIX in
 * the 100 hz periodic mode giving interrupts 100 times/second.
 *
 * Reading clk_hsec latches the the time in all the other bytes
 * so you get a consistent value.  To see any byte change, you
 * have to read clk_hsec in between (e.g. you can't loop waiting
 * for clk_sec to reach a certain value without reading clk_hsec
 * each time).
 */

#define	SECDAY	((unsigned)(24*60*60))		/* seconds per day */
#define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */

/*
 * The 7170 uses year % 4 to figure out if
 * we have a leap year, we do the same here.
 */
#define	SECYEAR(yr)	((((unsigned)(yr) % 4) == 0)? SECYR + SECDAY : SECYR)

/*
 * The year register counts from 0 to 99.
 * Unix time is the number of seconds
 * since the year YRREF.  The 2 digit year
 * value stored in the chip represents the 
 * the number of years beyond YRBASE.
 * Note that YRBASE must be < YRREF and
 * (YRBASE % 4) == 0 to do leap years correct.
 * Note that we can only keep time up to the year 2068.
 */
#define	YRREF		70	/* 1970 - where UNIX time begins */
#define	YRBASE		68	/* 1968 - what year 0 in chip represents */

#define	OBIO_CLOCK_ADDR	0xF3000000	/* address of clock in obio space */

#define	CLOCK0_ADDR	(MDEVBASE)	/* virtual address mapped to */

#ifndef LOCORE
struct intersil7170 {
	u_char	clk_hsec;	/* counter - hundredths of seconds 0-99 */
	u_char	clk_hour;	/* counter - hours 0-23 (24hr) 1-12 (12hr) */
	u_char	clk_min;	/* counter - minutes 0-59 */
	u_char	clk_sec;	/* counter - seconds 0-59 */
	u_char	clk_mon;	/* counter - month 1-12 */
	u_char	clk_day;	/* counter - day 1-31 */
	u_char	clk_year;	/* counter - year 0-99 */
	u_char	clk_weekday;	/* counter - week day 0-6 */
	u_char	clk_rhsec;	/* RAM - hundredths of seconds 0-99 */
	u_char	clk_rhour;	/* RAM - hours 0-23 (24hr) 1-12 (12hr) */
	u_char	clk_rmin;	/* RAM - minutes 0-59 */
	u_char	clk_rsec;	/* RAM - seconds 0-59 */
	u_char	clk_rmon;	/* RAM - month 1-12 */
	u_char	clk_rday;	/* RAM - day 1-31 */
	u_char	clk_ryear;	/* RAM - year 0-99 */
	u_char	clk_rweekday;	/* RAM - week day 0-6 */
	u_char	clk_intrreg;	/* interrupt status and mask register */
	u_char	clk_cmd;	/* command register */
	u_char	clk_unused[14];
};
#define	CLOCK0 ((struct intersil7170 *)(CLOCK0_ADDR))
#endif !LOCORE

/* offsets into structure */
#define	CLK_HSEC	0
#define	CLK_HOUR	1
#define	CLK_MIN		2
#define	CLK_SEC		3
#define	CLK_MON		4
#define	CLK_DAY		5
#define	CLK_YEAR	6
#define	CLK_WEEKDAY	7
#define	CLK_RHSEC	8
#define	CLK_RHOUR	9
#define	CLK_RMIN	10
#define	CLK_RSEC	11
#define	CLK_RMON	12
#define	CLK_RDAY	13
#define	CLK_RYEAR	14
#define	CLK_RWEEKDAY	15
#define	CLK_INTRREG	16
#define	CLK_CMD		17

/*
 * In `alarm' mode the 7170 interrupts when the current
 * counter matches the RAM values.  However, if the ignore
 * bit is on in the RAM counter, that register is not
 * used in the comparision.  Unfortunately, the clk_rhour
 * register uses a different mask bit (because of 12 hour
 * mode) and thus the 2 different defines.
 */
#define	CLK_IGNORE	0x80	/* rmsec, rmin, rsec, rmon, rday, ryear, rdow */
#define	CLK_HOUR_IGNORE	0x40	/* ignore bit for clk_rhour only */

/*
 * Interrupt status and mask register defines,
 * reading this register tells what caused an interrupt
 * and then clears the state.  These can occur
 * concurrently including te RAM compare interrupts.
 */
#define	CLK_INT_INTR	0x80	/* r/o pending interrrupt */
#define	CLK_INT_DAY	0x40	/* r/w periodic day interrupt */
#define	CLK_INT_HOUR	0x20	/* r/w periodic hour interrupt */
#define	CLK_INT_MIN	0x10	/* r/w periodic minute interrupt */
#define	CLK_INT_SEC	0x08	/* r/w periodic second interrupt */
#define	CLK_INT_TSEC	0x04	/* r/w periodic 1/10 second interrupt */
#define	CLK_INT_HSEC	0x02	/* r/w periodic 1/100 second interrupt */
#define	CLK_INT_ALARM	0x01	/* r/w alarm mode - interrupt on time match */

/* Command register defines */
#define	CLK_CMD_TEST	0x20	/* w/o test mode (vs. normal mode) */
#define	CLK_CMD_INTRENA	0x10	/* w/o interrupt enable (vs. disabled) */
#define	CLK_CMD_RUN	0x08	/* w/o run bit (vs. stop) */
#define	CLK_CMD_24FMT	0x04	/* w/o 24 hour format (vs. 12 hour format) */
#define	CLK_CMD_F4M	0x03	/* w/o using 4.194304MHz crystal frequency */
#define	CLK_CMD_F2M	0x02	/* w/o using 2.097152MHz crystal frequency */
#define	CLK_CMD_F1M	0x01	/* w/o using 1.048576MHz crystal frequency */
#define	CLK_CMD_F32K	0x00	/* w/o using  32.768KHz  crystal frequency */

#define	CLK_CMD_NORMAL	(CLK_CMD_INTRENA|CLK_CMD_RUN|CLK_CMD_24FMT|CLK_CMD_F32K)

/*
 * Definitions for the Mostek 48T02.  This chip is used for the time of
 * day service (battery backed up) and combines the eeprom and TOD.
 * Machines that use this chip also include hi resolution counters which
 * provide the real-time clock.  These counters are normally used to
 * generate 100hz clock interrupts, but are fully programmable for
 * whatever purpose desired.
 */
#define	CLOCK1_ADDR	(MDEVBASE + 0x27F8)
#ifndef	LOCORE
struct mostek48T02 {
	u_char	clk_ctrl;
	u_char	clk_sec;
	u_char	clk_min;
	u_char	clk_hour;
	u_char	clk_weekday;
	u_char	clk_day;
	u_char	clk_month;
	u_char	clk_year;
};
#define	CLOCK1 ((struct mostek48T02 *)(CLOCK1_ADDR))
#endif	!LOCORE

#define	CLK_CTRL_WRITE		0x80
#define	CLK_CTRL_READ		0x40
#define	CLK_CTRL_SIGN		0x20

#define	CLK_STOP		0x80
#define	CLK_KICK		0x80
#define	CLK_FREQT		0x40

#define	CLK_MONTH_MASK		0x1f
#define	CLK_DAY_MASK		0x3f
#define	CLK_WEEKDAY_MASK	0x07
#define	CLK_HOUR_MASK		0x3f
#define	CLK_MIN_MASK		0x7f
#define	CLK_SEC_MASK		0x7f

#define	OBIO_COUNTER_ADDR	0xEF000000
#define	COUNTER_ADDR		(MDEVBASE + 0xA000)

#ifndef	LOCORE
struct counterregs {
	u_int	counter10;
	u_int	limit10;
	u_int	counter14;
	u_int	limit14;
};
#define	COUNTER ((struct counterregs *)(COUNTER_ADDR))
#endif	!LOCORE

#define	CTR_LIMIT_BIT		0x80000000	/* limit bit mask */
#define	CTR_USEC_MASK		0x7FFFFC00	/* counter/limit mask */
#define	CTR_USEC_SHIFT		10		/* counter/limit shift */
 
/*
 * Offsets into counter register structure.
 */
#define	COUNT10			0
#define	LIM10			4
#define	COUNT14			8
#define	LIM14			12
 
#endif /*!_sun4_clock_h*/
