diff options
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/kernel/rtc.c | 69 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi.c | 24 | ||||
-rw-r--r-- | arch/x86/platform/mrst/vrtc.c | 44 |
4 files changed, 55 insertions, 83 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a4f24f5b1218..26bd79261532 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -120,6 +120,7 @@ config X86 | |||
120 | select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION | 120 | select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION |
121 | select OLD_SIGACTION if X86_32 | 121 | select OLD_SIGACTION if X86_32 |
122 | select COMPAT_OLD_SIGACTION if IA32_EMULATION | 122 | select COMPAT_OLD_SIGACTION if IA32_EMULATION |
123 | select RTC_LIB | ||
123 | 124 | ||
124 | config INSTRUCTION_DECODER | 125 | config INSTRUCTION_DECODER |
125 | def_bool y | 126 | def_bool y |
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 2e8f3d3b5641..198eb201ed3b 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <asm/x86_init.h> | 13 | #include <asm/x86_init.h> |
14 | #include <asm/time.h> | 14 | #include <asm/time.h> |
15 | #include <asm/mrst.h> | 15 | #include <asm/mrst.h> |
16 | #include <asm/rtc.h> | ||
16 | 17 | ||
17 | #ifdef CONFIG_X86_32 | 18 | #ifdef CONFIG_X86_32 |
18 | /* | 19 | /* |
@@ -36,70 +37,24 @@ EXPORT_SYMBOL(rtc_lock); | |||
36 | * nowtime is written into the registers of the CMOS clock, it will | 37 | * nowtime is written into the registers of the CMOS clock, it will |
37 | * jump to the next second precisely 500 ms later. Check the Motorola | 38 | * jump to the next second precisely 500 ms later. Check the Motorola |
38 | * MC146818A or Dallas DS12887 data sheet for details. | 39 | * MC146818A or Dallas DS12887 data sheet for details. |
39 | * | ||
40 | * BUG: This routine does not handle hour overflow properly; it just | ||
41 | * sets the minutes. Usually you'll only notice that after reboot! | ||
42 | */ | 40 | */ |
43 | int mach_set_rtc_mmss(unsigned long nowtime) | 41 | int mach_set_rtc_mmss(unsigned long nowtime) |
44 | { | 42 | { |
45 | int real_seconds, real_minutes, cmos_minutes; | 43 | struct rtc_time tm; |
46 | unsigned char save_control, save_freq_select; | ||
47 | unsigned long flags; | ||
48 | int retval = 0; | 44 | int retval = 0; |
49 | 45 | ||
50 | spin_lock_irqsave(&rtc_lock, flags); | 46 | rtc_time_to_tm(nowtime, &tm); |
51 | 47 | if (!rtc_valid_tm(&tm)) { | |
52 | /* tell the clock it's being set */ | 48 | retval = set_rtc_time(&tm); |
53 | save_control = CMOS_READ(RTC_CONTROL); | 49 | if (retval) |
54 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 50 | printk(KERN_ERR "%s: RTC write failed with error %d\n", |
55 | 51 | __FUNCTION__, retval); | |
56 | /* stop and reset prescaler */ | ||
57 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
58 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
59 | |||
60 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
61 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
62 | cmos_minutes = bcd2bin(cmos_minutes); | ||
63 | |||
64 | /* | ||
65 | * since we're only adjusting minutes and seconds, | ||
66 | * don't interfere with hour overflow. This avoids | ||
67 | * messing with unknown time zones but requires your | ||
68 | * RTC not to be off by more than 15 minutes | ||
69 | */ | ||
70 | real_seconds = nowtime % 60; | ||
71 | real_minutes = nowtime / 60; | ||
72 | /* correct for half hour time zone */ | ||
73 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
74 | real_minutes += 30; | ||
75 | real_minutes %= 60; | ||
76 | |||
77 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
78 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
79 | real_seconds = bin2bcd(real_seconds); | ||
80 | real_minutes = bin2bcd(real_minutes); | ||
81 | } | ||
82 | CMOS_WRITE(real_seconds, RTC_SECONDS); | ||
83 | CMOS_WRITE(real_minutes, RTC_MINUTES); | ||
84 | } else { | 52 | } else { |
85 | printk_once(KERN_NOTICE | 53 | printk(KERN_ERR |
86 | "set_rtc_mmss: can't update from %d to %d\n", | 54 | "%s: Invalid RTC value: write of %lx to RTC failed\n", |
87 | cmos_minutes, real_minutes); | 55 | __FUNCTION__, nowtime); |
88 | retval = -1; | 56 | retval = -EINVAL; |
89 | } | 57 | } |
90 | |||
91 | /* The following flags have to be released exactly in this order, | ||
92 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
93 | * battery and quartz) will not reset the oscillator and will not | ||
94 | * update precisely 500 ms later. You won't find this mentioned in | ||
95 | * the Dallas Semiconductor data sheets, but who believes data | ||
96 | * sheets anyway ... -- Markus Kuhn | ||
97 | */ | ||
98 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
99 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
100 | |||
101 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
102 | |||
103 | return retval; | 58 | return retval; |
104 | } | 59 | } |
105 | 60 | ||
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 5f2ecaf3f9d8..28d9efacc9b6 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <asm/cacheflush.h> | 48 | #include <asm/cacheflush.h> |
49 | #include <asm/tlbflush.h> | 49 | #include <asm/tlbflush.h> |
50 | #include <asm/x86_init.h> | 50 | #include <asm/x86_init.h> |
51 | #include <asm/rtc.h> | ||
51 | 52 | ||
52 | #define EFI_DEBUG 1 | 53 | #define EFI_DEBUG 1 |
53 | 54 | ||
@@ -258,10 +259,10 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm, | |||
258 | 259 | ||
259 | int efi_set_rtc_mmss(unsigned long nowtime) | 260 | int efi_set_rtc_mmss(unsigned long nowtime) |
260 | { | 261 | { |
261 | int real_seconds, real_minutes; | ||
262 | efi_status_t status; | 262 | efi_status_t status; |
263 | efi_time_t eft; | 263 | efi_time_t eft; |
264 | efi_time_cap_t cap; | 264 | efi_time_cap_t cap; |
265 | struct rtc_time tm; | ||
265 | 266 | ||
266 | status = efi.get_time(&eft, &cap); | 267 | status = efi.get_time(&eft, &cap); |
267 | if (status != EFI_SUCCESS) { | 268 | if (status != EFI_SUCCESS) { |
@@ -269,13 +270,20 @@ int efi_set_rtc_mmss(unsigned long nowtime) | |||
269 | return -1; | 270 | return -1; |
270 | } | 271 | } |
271 | 272 | ||
272 | real_seconds = nowtime % 60; | 273 | rtc_time_to_tm(nowtime, &tm); |
273 | real_minutes = nowtime / 60; | 274 | if (!rtc_valid_tm(&tm)) { |
274 | if (((abs(real_minutes - eft.minute) + 15)/30) & 1) | 275 | eft.year = tm.tm_year + 1900; |
275 | real_minutes += 30; | 276 | eft.month = tm.tm_mon + 1; |
276 | real_minutes %= 60; | 277 | eft.day = tm.tm_mday; |
277 | eft.minute = real_minutes; | 278 | eft.minute = tm.tm_min; |
278 | eft.second = real_seconds; | 279 | eft.second = tm.tm_sec; |
280 | eft.nanosecond = 0; | ||
281 | } else { | ||
282 | printk(KERN_ERR | ||
283 | "%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n", | ||
284 | __FUNCTION__, nowtime); | ||
285 | return -1; | ||
286 | } | ||
279 | 287 | ||
280 | status = efi.set_time(&eft); | 288 | status = efi.set_time(&eft); |
281 | if (status != EFI_SUCCESS) { | 289 | if (status != EFI_SUCCESS) { |
diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c index 225bd0f0f675..d62b0a3b5c14 100644 --- a/arch/x86/platform/mrst/vrtc.c +++ b/arch/x86/platform/mrst/vrtc.c | |||
@@ -85,27 +85,35 @@ unsigned long vrtc_get_time(void) | |||
85 | return mktime(year, mon, mday, hour, min, sec); | 85 | return mktime(year, mon, mday, hour, min, sec); |
86 | } | 86 | } |
87 | 87 | ||
88 | /* Only care about the minutes and seconds */ | ||
89 | int vrtc_set_mmss(unsigned long nowtime) | 88 | int vrtc_set_mmss(unsigned long nowtime) |
90 | { | 89 | { |
91 | int real_sec, real_min; | ||
92 | unsigned long flags; | 90 | unsigned long flags; |
93 | int vrtc_min; | 91 | struct rtc_time tm; |
94 | 92 | int year; | |
95 | spin_lock_irqsave(&rtc_lock, flags); | 93 | int retval = 0; |
96 | vrtc_min = vrtc_cmos_read(RTC_MINUTES); | 94 | |
97 | 95 | rtc_time_to_tm(nowtime, &tm); | |
98 | real_sec = nowtime % 60; | 96 | if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) { |
99 | real_min = nowtime / 60; | 97 | /* |
100 | if (((abs(real_min - vrtc_min) + 15)/30) & 1) | 98 | * tm.year is the number of years since 1900, and the |
101 | real_min += 30; | 99 | * vrtc need the years since 1972. |
102 | real_min %= 60; | 100 | */ |
103 | 101 | year = tm.tm_year - 72; | |
104 | vrtc_cmos_write(real_sec, RTC_SECONDS); | 102 | spin_lock_irqsave(&rtc_lock, flags); |
105 | vrtc_cmos_write(real_min, RTC_MINUTES); | 103 | vrtc_cmos_write(year, RTC_YEAR); |
106 | spin_unlock_irqrestore(&rtc_lock, flags); | 104 | vrtc_cmos_write(tm.tm_mon, RTC_MONTH); |
107 | 105 | vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH); | |
108 | return 0; | 106 | vrtc_cmos_write(tm.tm_hour, RTC_HOURS); |
107 | vrtc_cmos_write(tm.tm_min, RTC_MINUTES); | ||
108 | vrtc_cmos_write(tm.tm_sec, RTC_SECONDS); | ||
109 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
110 | } else { | ||
111 | printk(KERN_ERR | ||
112 | "%s: Invalid vRTC value: write of %lx to vRTC failed\n", | ||
113 | __FUNCTION__, nowtime); | ||
114 | retval = -EINVAL; | ||
115 | } | ||
116 | return retval; | ||
109 | } | 117 | } |
110 | 118 | ||
111 | void __init mrst_rtc_init(void) | 119 | void __init mrst_rtc_init(void) |