These changes are the raw update to qemu-2.6.
[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     index |= NMI_DISABLE_BIT;
34     outb(index, PORT_CMOS_INDEX);
35     u8 val = inb(PORT_CMOS_DATA);
36     outb((val & ~off) | on, PORT_CMOS_DATA);
37 }
38
39 int
40 rtc_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
63 void
64 rtc_setup(void)
65 {
66     if (!CONFIG_RTC_TIMER)
67         return;
68     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
74 int RTCusers VARLOW;
75
76 void
77 rtc_use(void)
78 {
79     if (!CONFIG_RTC_TIMER)
80         return;
81     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
89 void
90 rtc_release(void)
91 {
92     if (!CONFIG_RTC_TIMER)
93         return;
94     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 }