1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * RTC related functions |
4 | */ |
5 | #include <linux/platform_device.h> |
6 | #include <linux/mc146818rtc.h> |
7 | #include <linux/export.h> |
8 | #include <linux/pnp.h> |
9 | |
10 | #include <asm/vsyscall.h> |
11 | #include <asm/x86_init.h> |
12 | #include <asm/time.h> |
13 | #include <asm/intel-mid.h> |
14 | #include <asm/setup.h> |
15 | |
16 | #ifdef CONFIG_X86_32 |
17 | /* |
18 | * This is a special lock that is owned by the CPU and holds the index |
19 | * register we are working with. It is required for NMI access to the |
20 | * CMOS/RTC registers. See arch/x86/include/asm/mc146818rtc.h for details. |
21 | */ |
22 | volatile unsigned long cmos_lock; |
23 | EXPORT_SYMBOL(cmos_lock); |
24 | #endif /* CONFIG_X86_32 */ |
25 | |
26 | DEFINE_SPINLOCK(rtc_lock); |
27 | EXPORT_SYMBOL(rtc_lock); |
28 | |
29 | /* |
30 | * In order to set the CMOS clock precisely, mach_set_cmos_time has to be |
31 | * called 500 ms after the second nowtime has started, because when |
32 | * nowtime is written into the registers of the CMOS clock, it will |
33 | * jump to the next second precisely 500 ms later. Check the Motorola |
34 | * MC146818A or Dallas DS12887 data sheet for details. |
35 | */ |
36 | int mach_set_cmos_time(const struct timespec64 *now) |
37 | { |
38 | unsigned long long nowtime = now->tv_sec; |
39 | struct rtc_time tm; |
40 | int retval = 0; |
41 | |
42 | rtc_time64_to_tm(time: nowtime, tm: &tm); |
43 | if (!rtc_valid_tm(tm: &tm)) { |
44 | retval = mc146818_set_time(time: &tm); |
45 | if (retval) |
46 | printk(KERN_ERR "%s: RTC write failed with error %d\n" , |
47 | __func__, retval); |
48 | } else { |
49 | printk(KERN_ERR |
50 | "%s: Invalid RTC value: write of %llx to RTC failed\n" , |
51 | __func__, nowtime); |
52 | retval = -EINVAL; |
53 | } |
54 | return retval; |
55 | } |
56 | |
57 | void mach_get_cmos_time(struct timespec64 *now) |
58 | { |
59 | struct rtc_time tm; |
60 | |
61 | /* |
62 | * If pm_trace abused the RTC as storage, set the timespec to 0, |
63 | * which tells the caller that this RTC value is unusable. |
64 | */ |
65 | if (!pm_trace_rtc_valid()) { |
66 | now->tv_sec = now->tv_nsec = 0; |
67 | return; |
68 | } |
69 | |
70 | if (mc146818_get_time(time: &tm, timeout: 1000)) { |
71 | pr_err("Unable to read current time from RTC\n" ); |
72 | now->tv_sec = now->tv_nsec = 0; |
73 | return; |
74 | } |
75 | |
76 | now->tv_sec = rtc_tm_to_time64(tm: &tm); |
77 | now->tv_nsec = 0; |
78 | } |
79 | |
80 | /* Routines for accessing the CMOS RAM/RTC. */ |
81 | unsigned char rtc_cmos_read(unsigned char addr) |
82 | { |
83 | unsigned char val; |
84 | |
85 | lock_cmos_prefix(addr); |
86 | outb(value: addr, RTC_PORT(0)); |
87 | val = inb(RTC_PORT(1)); |
88 | lock_cmos_suffix(addr); |
89 | |
90 | return val; |
91 | } |
92 | EXPORT_SYMBOL(rtc_cmos_read); |
93 | |
94 | void rtc_cmos_write(unsigned char val, unsigned char addr) |
95 | { |
96 | lock_cmos_prefix(addr); |
97 | outb(value: addr, RTC_PORT(0)); |
98 | outb(value: val, RTC_PORT(1)); |
99 | lock_cmos_suffix(addr); |
100 | } |
101 | EXPORT_SYMBOL(rtc_cmos_write); |
102 | |
103 | int update_persistent_clock64(struct timespec64 now) |
104 | { |
105 | return x86_platform.set_wallclock(&now); |
106 | } |
107 | |
108 | /* not static: needed by APM */ |
109 | void read_persistent_clock64(struct timespec64 *ts) |
110 | { |
111 | x86_platform.get_wallclock(ts); |
112 | } |
113 | |
114 | |
115 | static struct resource rtc_resources[] = { |
116 | [0] = { |
117 | .start = RTC_PORT(0), |
118 | .end = RTC_PORT(1), |
119 | .flags = IORESOURCE_IO, |
120 | }, |
121 | [1] = { |
122 | .start = RTC_IRQ, |
123 | .end = RTC_IRQ, |
124 | .flags = IORESOURCE_IRQ, |
125 | } |
126 | }; |
127 | |
128 | static struct platform_device rtc_device = { |
129 | .name = "rtc_cmos" , |
130 | .id = -1, |
131 | .resource = rtc_resources, |
132 | .num_resources = ARRAY_SIZE(rtc_resources), |
133 | }; |
134 | |
135 | static __init int add_rtc_cmos(void) |
136 | { |
137 | #ifdef CONFIG_PNP |
138 | static const char * const ids[] __initconst = |
139 | { "PNP0b00" , "PNP0b01" , "PNP0b02" , }; |
140 | struct pnp_dev *dev; |
141 | int i; |
142 | |
143 | pnp_for_each_dev(dev) { |
144 | for (i = 0; i < ARRAY_SIZE(ids); i++) { |
145 | if (compare_pnp_id(pos: dev->id, id: ids[i]) != 0) |
146 | return 0; |
147 | } |
148 | } |
149 | #endif |
150 | if (!x86_platform.legacy.rtc) |
151 | return -ENODEV; |
152 | |
153 | platform_device_register(&rtc_device); |
154 | dev_info(&rtc_device.dev, |
155 | "registered platform RTC device (no PNP device found)\n" ); |
156 | |
157 | return 0; |
158 | } |
159 | device_initcall(add_rtc_cmos); |
160 | |