3 * Denis Peter MPL AG Switzerland. d.peter@mpl.ch
5 * SPDX-License-Identifier: GPL-2.0+
9 * Date & Time support for the MC146818 (PIXX4) RTC
17 #if defined(__I386__) || defined(CONFIG_MALTA)
20 #define out8(p, v) outb(v, p)
23 #if defined(CONFIG_CMD_DATE)
25 /* Set this to 1 to clear the CMOS RAM */
28 #define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70
29 #define RTC_SECONDS 0x00
30 #define RTC_SECONDS_ALARM 0x01
31 #define RTC_MINUTES 0x02
32 #define RTC_MINUTES_ALARM 0x03
33 #define RTC_HOURS 0x04
34 #define RTC_HOURS_ALARM 0x05
35 #define RTC_DAY_OF_WEEK 0x06
36 #define RTC_DATE_OF_MONTH 0x07
37 #define RTC_MONTH 0x08
39 #define RTC_CONFIG_A 0x0a
40 #define RTC_CONFIG_B 0x0b
41 #define RTC_CONFIG_C 0x0c
42 #define RTC_CONFIG_D 0x0d
43 #define RTC_REG_SIZE 0x80
45 #define RTC_CONFIG_A_REF_CLCK_32KHZ (1 << 5)
46 #define RTC_CONFIG_A_RATE_1024HZ 6
48 #define RTC_CONFIG_B_24H (1 << 1)
50 #define RTC_CONFIG_D_VALID_RAM_AND_TIME 0x80
52 static int mc146818_read8(int reg
)
54 #ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
55 return in8(CONFIG_SYS_RTC_REG_BASE_ADDR
+ reg
);
63 out8(RTC_PORT_MC146818
+ ofs
, reg
);
65 return in8(RTC_PORT_MC146818
+ ofs
+ 1);
69 static void mc146818_write8(int reg
, uchar val
)
71 #ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
72 out8(CONFIG_SYS_RTC_REG_BASE_ADDR
+ reg
, val
);
80 out8(RTC_PORT_MC146818
+ ofs
, reg
);
81 out8(RTC_PORT_MC146818
+ ofs
+ 1, val
);
85 static int mc146818_get(struct rtc_time
*tmp
)
87 uchar sec
, min
, hour
, mday
, wday
, mon
, year
;
89 /* here check if rtc can be accessed */
90 while ((mc146818_read8(RTC_CONFIG_A
) & 0x80) == 0x80)
93 sec
= mc146818_read8(RTC_SECONDS
);
94 min
= mc146818_read8(RTC_MINUTES
);
95 hour
= mc146818_read8(RTC_HOURS
);
96 mday
= mc146818_read8(RTC_DATE_OF_MONTH
);
97 wday
= mc146818_read8(RTC_DAY_OF_WEEK
);
98 mon
= mc146818_read8(RTC_MONTH
);
99 year
= mc146818_read8(RTC_YEAR
);
101 printf("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x hr: %02x min: %02x sec: %02x\n",
102 year
, mon
, mday
, wday
, hour
, min
, sec
);
103 printf("Alarms: month: %02x hour: %02x min: %02x sec: %02x\n",
104 mc146818_read8(RTC_CONFIG_D
) & 0x3f,
105 mc146818_read8(RTC_HOURS_ALARM
),
106 mc146818_read8(RTC_MINUTES_ALARM
),
107 mc146818_read8(RTC_SECONDS_ALARM
));
109 tmp
->tm_sec
= bcd2bin(sec
& 0x7f);
110 tmp
->tm_min
= bcd2bin(min
& 0x7f);
111 tmp
->tm_hour
= bcd2bin(hour
& 0x3f);
112 tmp
->tm_mday
= bcd2bin(mday
& 0x3f);
113 tmp
->tm_mon
= bcd2bin(mon
& 0x1f);
114 tmp
->tm_year
= bcd2bin(year
);
115 tmp
->tm_wday
= bcd2bin(wday
& 0x07);
117 if (tmp
->tm_year
< 70)
118 tmp
->tm_year
+= 2000;
120 tmp
->tm_year
+= 1900;
125 printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
126 tmp
->tm_year
, tmp
->tm_mon
, tmp
->tm_mday
, tmp
->tm_wday
,
127 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
);
133 static int mc146818_set(struct rtc_time
*tmp
)
136 printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
137 tmp
->tm_year
, tmp
->tm_mon
, tmp
->tm_mday
, tmp
->tm_wday
,
138 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
);
140 /* Disable the RTC to update the regs */
141 mc146818_write8(RTC_CONFIG_B
, 0x82);
143 mc146818_write8(RTC_YEAR
, bin2bcd(tmp
->tm_year
% 100));
144 mc146818_write8(RTC_MONTH
, bin2bcd(tmp
->tm_mon
));
145 mc146818_write8(RTC_DAY_OF_WEEK
, bin2bcd(tmp
->tm_wday
));
146 mc146818_write8(RTC_DATE_OF_MONTH
, bin2bcd(tmp
->tm_mday
));
147 mc146818_write8(RTC_HOURS
, bin2bcd(tmp
->tm_hour
));
148 mc146818_write8(RTC_MINUTES
, bin2bcd(tmp
->tm_min
));
149 mc146818_write8(RTC_SECONDS
, bin2bcd(tmp
->tm_sec
));
151 /* Enable the RTC to update the regs */
152 mc146818_write8(RTC_CONFIG_B
, 0x02);
157 static void mc146818_reset(void)
159 /* Disable the RTC to update the regs */
160 mc146818_write8(RTC_CONFIG_B
, 0x82);
163 mc146818_write8(RTC_CONFIG_A
, 0x20);
164 mc146818_write8(RTC_CONFIG_B
, 0x00);
165 mc146818_write8(RTC_CONFIG_B
, 0x00);
167 /* Enable the RTC to update the regs */
168 mc146818_write8(RTC_CONFIG_B
, 0x02);
171 static void mc146818_init(void)
176 rtc_write8(RTC_SECONDS_ALARM
, 0);
177 rtc_write8(RTC_MINUTES_ALARM
, 0);
178 rtc_write8(RTC_HOURS_ALARM
, 0);
179 for (i
= RTC_CONFIG_A
; i
< RTC_REG_SIZE
; i
++)
181 printf("RTC: zeroing CMOS RAM\n");
184 /* Setup the real time clock */
185 mc146818_write8(RTC_CONFIG_B
, RTC_CONFIG_B_24H
);
186 /* Setup the frequency it operates at */
187 mc146818_write8(RTC_CONFIG_A
, RTC_CONFIG_A_REF_CLCK_32KHZ
|
188 RTC_CONFIG_A_RATE_1024HZ
);
189 /* Ensure all reserved bits are 0 in register D */
190 mc146818_write8(RTC_CONFIG_D
, RTC_CONFIG_D_VALID_RAM_AND_TIME
);
192 /* Clear any pending interrupts */
193 mc146818_read8(RTC_CONFIG_C
);
195 #endif /* CONFIG_CMD_DATE */
199 static int rtc_mc146818_get(struct udevice
*dev
, struct rtc_time
*time
)
201 return mc146818_get(time
);
204 static int rtc_mc146818_set(struct udevice
*dev
, const struct rtc_time
*time
)
206 return mc146818_set((struct rtc_time
*)time
);
209 static int rtc_mc146818_reset(struct udevice
*dev
)
216 static int rtc_mc146818_read8(struct udevice
*dev
, unsigned int reg
)
218 return mc146818_read8(reg
);
221 static int rtc_mc146818_write8(struct udevice
*dev
, unsigned int reg
, int val
)
223 mc146818_write8(reg
, val
);
228 static int rtc_mc146818_probe(struct udevice
*dev
)
235 static const struct rtc_ops rtc_mc146818_ops
= {
236 .get
= rtc_mc146818_get
,
237 .set
= rtc_mc146818_set
,
238 .reset
= rtc_mc146818_reset
,
239 .read8
= rtc_mc146818_read8
,
240 .write8
= rtc_mc146818_write8
,
243 static const struct udevice_id rtc_mc146818_ids
[] = {
244 { .compatible
= "motorola,mc146818" },
248 U_BOOT_DRIVER(rtc_mc146818
) = {
249 .name
= "rtc_mc146818",
251 .of_match
= rtc_mc146818_ids
,
252 .probe
= rtc_mc146818_probe
,
253 .ops
= &rtc_mc146818_ops
,
256 #else /* !CONFIG_DM_RTC */
258 int rtc_get(struct rtc_time
*tmp
)
260 return mc146818_get(tmp
);
263 int rtc_set(struct rtc_time
*tmp
)
265 return mc146818_set(tmp
);
273 int rtc_read8(int reg
)
275 return mc146818_read8(reg
);
278 void rtc_write8(int reg
, uchar val
)
280 mc146818_write8(reg
, val
);
283 u32
rtc_read32(int reg
)
288 for (i
= 0; i
< sizeof(value
); i
++)
289 value
|= rtc_read8(reg
+ i
) << (i
<< 3);
294 void rtc_write32(int reg
, u32 value
)
298 for (i
= 0; i
< sizeof(value
); i
++)
299 rtc_write8(reg
+ i
, (value
>> (i
<< 3)) & 0xff);
307 #endif /* CONFIG_DM_RTC */