blob: 9649a5a793a7d0c90e3aad3c03f7129fac5a9d01 [file] [log] [blame]
Kevin O'Connor8b7861c2013-09-15 02:29:06 -04001// Support for MC146818 Real Time Clock chip.
2//
3// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
6// This file may be distributed under the terms of the GNU LGPLv3 license.
7
8#include "biosvar.h" // GET_LOW
Kevin O'Connor8b7861c2013-09-15 02:29:06 -04009#include "rtc.h" // rtc_read
10#include "stacks.h" // yield
11#include "util.h" // timer_calc
Kevin O'Connor4ade5232013-09-18 21:41:48 -040012#include "x86.h" // inb
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040013
14u8
15rtc_read(u8 index)
16{
17 index |= NMI_DISABLE_BIT;
18 outb(index, PORT_CMOS_INDEX);
19 return inb(PORT_CMOS_DATA);
20}
21
22void
23rtc_write(u8 index, u8 val)
24{
25 index |= NMI_DISABLE_BIT;
26 outb(index, PORT_CMOS_INDEX);
27 outb(val, PORT_CMOS_DATA);
28}
29
30void
31rtc_mask(u8 index, u8 off, u8 on)
32{
Kevin O'Connor3156b712015-09-01 19:43:08 -040033 index |= NMI_DISABLE_BIT;
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040034 outb(index, PORT_CMOS_INDEX);
35 u8 val = inb(PORT_CMOS_DATA);
36 outb((val & ~off) | on, PORT_CMOS_DATA);
37}
38
39int
40rtc_updating(void)
41{
42 // This function checks to see if the update-in-progress bit
43 // is set in CMOS Status Register A. If not, it returns 0.
44 // If it is set, it tries to wait until there is a transition
45 // to 0, and will return 0 if such a transition occurs. A -1
46 // is returned only after timing out. The maximum period
47 // that this bit should be set is constrained to (1984+244)
48 // useconds, but we wait for longer just to be sure.
49
50 if ((rtc_read(CMOS_STATUS_A) & RTC_A_UIP) == 0)
51 return 0;
52 u32 end = timer_calc(15);
53 for (;;) {
54 if ((rtc_read(CMOS_STATUS_A) & RTC_A_UIP) == 0)
55 return 0;
56 if (timer_check(end))
57 // update-in-progress never transitioned to 0
58 return -1;
59 yield();
60 }
61}
62
63void
64rtc_setup(void)
65{
Kevin O'Connorbc46ebe2015-08-13 11:43:27 -040066 if (!CONFIG_RTC_TIMER)
67 return;
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040068 rtc_write(CMOS_STATUS_A, 0x26); // 32,768Khz src, 976.5625us updates
69 rtc_mask(CMOS_STATUS_B, ~RTC_B_DSE, RTC_B_24HR);
70 rtc_read(CMOS_STATUS_C);
71 rtc_read(CMOS_STATUS_D);
72}
73
74int RTCusers VARLOW;
75
76void
77rtc_use(void)
78{
Kevin O'Connorbc46ebe2015-08-13 11:43:27 -040079 if (!CONFIG_RTC_TIMER)
80 return;
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040081 int count = GET_LOW(RTCusers);
82 SET_LOW(RTCusers, count+1);
83 if (count)
84 return;
85 // Turn on the Periodic Interrupt timer
86 rtc_mask(CMOS_STATUS_B, 0, RTC_B_PIE);
87}
88
89void
90rtc_release(void)
91{
Kevin O'Connorbc46ebe2015-08-13 11:43:27 -040092 if (!CONFIG_RTC_TIMER)
93 return;
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040094 int count = GET_LOW(RTCusers);
95 SET_LOW(RTCusers, count-1);
96 if (count != 1)
97 return;
98 // Clear the Periodic Interrupt.
99 rtc_mask(CMOS_STATUS_B, RTC_B_PIE, 0);
100}