Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / hw / rtc.c
1 // 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
9 #include "rtc.h" // rtc_read
10 #include "stacks.h" // yield
11 #include "util.h" // timer_calc
12 #include "x86.h" // inb
13
14 u8
15 rtc_read(u8 index)
16 {
17     index |= NMI_DISABLE_BIT;
18     outb(index, PORT_CMOS_INDEX);
19     return inb(PORT_CMOS_DATA);
20 }
21
22 void
23 rtc_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
30 void
31 rtc_mask(u8 index, u8 off, u8 on)
32 {
33     outb(index, PORT_CMOS_INDEX);
34     u8 val = inb(PORT_CMOS_DATA);
35     outb((val & ~off) | on, PORT_CMOS_DATA);
36 }
37
38 int
39 rtc_updating(void)
40 {
41     // This function checks to see if the update-in-progress bit
42     // is set in CMOS Status Register A.  If not, it returns 0.
43     // If it is set, it tries to wait until there is a transition
44     // to 0, and will return 0 if such a transition occurs.  A -1
45     // is returned only after timing out.  The maximum period
46     // that this bit should be set is constrained to (1984+244)
47     // useconds, but we wait for longer just to be sure.
48
49     if ((rtc_read(CMOS_STATUS_A) & RTC_A_UIP) == 0)
50         return 0;
51     u32 end = timer_calc(15);
52     for (;;) {
53         if ((rtc_read(CMOS_STATUS_A) & RTC_A_UIP) == 0)
54             return 0;
55         if (timer_check(end))
56             // update-in-progress never transitioned to 0
57             return -1;
58         yield();
59     }
60 }
61
62 void
63 rtc_setup(void)
64 {
65     rtc_write(CMOS_STATUS_A, 0x26);    // 32,768Khz src, 976.5625us updates
66     rtc_mask(CMOS_STATUS_B, ~RTC_B_DSE, RTC_B_24HR);
67     rtc_read(CMOS_STATUS_C);
68     rtc_read(CMOS_STATUS_D);
69 }
70
71 int RTCusers VARLOW;
72
73 void
74 rtc_use(void)
75 {
76     int count = GET_LOW(RTCusers);
77     SET_LOW(RTCusers, count+1);
78     if (count)
79         return;
80     // Turn on the Periodic Interrupt timer
81     rtc_mask(CMOS_STATUS_B, 0, RTC_B_PIE);
82 }
83
84 void
85 rtc_release(void)
86 {
87     int count = GET_LOW(RTCusers);
88     SET_LOW(RTCusers, count-1);
89     if (count != 1)
90         return;
91     // Clear the Periodic Interrupt.
92     rtc_mask(CMOS_STATUS_B, RTC_B_PIE, 0);
93 }