0001
0002 #include <linux/bcd.h>
0003 #include <linux/delay.h>
0004 #include <linux/export.h>
0005 #include <linux/mc146818rtc.h>
0006
0007 #ifdef CONFIG_ACPI
0008 #include <linux/acpi.h>
0009 #endif
0010
0011
0012
0013
0014
0015
0016
0017 bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
0018 void *param)
0019 {
0020 int i;
0021 unsigned long flags;
0022 unsigned char seconds;
0023
0024 for (i = 0; i < 100; i++) {
0025 spin_lock_irqsave(&rtc_lock, flags);
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 seconds = CMOS_READ(RTC_SECONDS);
0037
0038 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
0039 spin_unlock_irqrestore(&rtc_lock, flags);
0040 udelay(100);
0041 continue;
0042 }
0043
0044
0045 if (seconds != CMOS_READ(RTC_SECONDS)) {
0046 spin_unlock_irqrestore(&rtc_lock, flags);
0047 continue;
0048 }
0049
0050 if (callback)
0051 callback(seconds, param);
0052
0053
0054
0055
0056
0057 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
0058 spin_unlock_irqrestore(&rtc_lock, flags);
0059 udelay(100);
0060 continue;
0061 }
0062
0063
0064
0065
0066
0067
0068
0069 if (seconds != CMOS_READ(RTC_SECONDS)) {
0070 spin_unlock_irqrestore(&rtc_lock, flags);
0071 continue;
0072 }
0073 spin_unlock_irqrestore(&rtc_lock, flags);
0074
0075 return true;
0076 }
0077 return false;
0078 }
0079 EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
0080
0081
0082
0083
0084
0085 bool mc146818_does_rtc_work(void)
0086 {
0087 return mc146818_avoid_UIP(NULL, NULL);
0088 }
0089 EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
0090
0091 struct mc146818_get_time_callback_param {
0092 struct rtc_time *time;
0093 unsigned char ctrl;
0094 #ifdef CONFIG_ACPI
0095 unsigned char century;
0096 #endif
0097 #ifdef CONFIG_MACH_DECSTATION
0098 unsigned int real_year;
0099 #endif
0100 };
0101
0102 static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
0103 {
0104 struct mc146818_get_time_callback_param *p = param_in;
0105
0106
0107
0108
0109
0110
0111
0112 p->time->tm_sec = seconds;
0113 p->time->tm_min = CMOS_READ(RTC_MINUTES);
0114 p->time->tm_hour = CMOS_READ(RTC_HOURS);
0115 p->time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
0116 p->time->tm_mon = CMOS_READ(RTC_MONTH);
0117 p->time->tm_year = CMOS_READ(RTC_YEAR);
0118 #ifdef CONFIG_MACH_DECSTATION
0119 p->real_year = CMOS_READ(RTC_DEC_YEAR);
0120 #endif
0121 #ifdef CONFIG_ACPI
0122 if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
0123 acpi_gbl_FADT.century) {
0124 p->century = CMOS_READ(acpi_gbl_FADT.century);
0125 } else {
0126 p->century = 0;
0127 }
0128 #endif
0129
0130 p->ctrl = CMOS_READ(RTC_CONTROL);
0131 }
0132
0133 int mc146818_get_time(struct rtc_time *time)
0134 {
0135 struct mc146818_get_time_callback_param p = {
0136 .time = time
0137 };
0138
0139 if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
0140 memset(time, 0, sizeof(*time));
0141 return -EIO;
0142 }
0143
0144 if (!(p.ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
0145 {
0146 time->tm_sec = bcd2bin(time->tm_sec);
0147 time->tm_min = bcd2bin(time->tm_min);
0148 time->tm_hour = bcd2bin(time->tm_hour);
0149 time->tm_mday = bcd2bin(time->tm_mday);
0150 time->tm_mon = bcd2bin(time->tm_mon);
0151 time->tm_year = bcd2bin(time->tm_year);
0152 #ifdef CONFIG_ACPI
0153 p.century = bcd2bin(p.century);
0154 #endif
0155 }
0156
0157 #ifdef CONFIG_MACH_DECSTATION
0158 time->tm_year += p.real_year - 72;
0159 #endif
0160
0161 #ifdef CONFIG_ACPI
0162 if (p.century > 19)
0163 time->tm_year += (p.century - 19) * 100;
0164 #endif
0165
0166
0167
0168
0169
0170 if (time->tm_year <= 69)
0171 time->tm_year += 100;
0172
0173 time->tm_mon--;
0174
0175 return 0;
0176 }
0177 EXPORT_SYMBOL_GPL(mc146818_get_time);
0178
0179
0180 static bool apply_amd_register_a_behavior(void)
0181 {
0182 #ifdef CONFIG_X86
0183 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
0184 boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
0185 return true;
0186 #endif
0187 return false;
0188 }
0189
0190
0191 int mc146818_set_time(struct rtc_time *time)
0192 {
0193 unsigned long flags;
0194 unsigned char mon, day, hrs, min, sec;
0195 unsigned char save_control, save_freq_select;
0196 unsigned int yrs;
0197 #ifdef CONFIG_MACH_DECSTATION
0198 unsigned int real_yrs, leap_yr;
0199 #endif
0200 unsigned char century = 0;
0201
0202 yrs = time->tm_year;
0203 mon = time->tm_mon + 1;
0204 day = time->tm_mday;
0205 hrs = time->tm_hour;
0206 min = time->tm_min;
0207 sec = time->tm_sec;
0208
0209 if (yrs > 255)
0210 return -EINVAL;
0211
0212 #ifdef CONFIG_MACH_DECSTATION
0213 real_yrs = yrs;
0214 leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
0215 !((yrs + 1900) % 400));
0216 yrs = 72;
0217
0218
0219
0220
0221
0222
0223 if (!leap_yr && mon < 3) {
0224 real_yrs--;
0225 yrs = 73;
0226 }
0227 #endif
0228
0229 #ifdef CONFIG_ACPI
0230 if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
0231 acpi_gbl_FADT.century) {
0232 century = (yrs + 1900) / 100;
0233 yrs %= 100;
0234 }
0235 #endif
0236
0237
0238
0239
0240 if (yrs > 169)
0241 return -EINVAL;
0242
0243 if (yrs >= 100)
0244 yrs -= 100;
0245
0246 spin_lock_irqsave(&rtc_lock, flags);
0247 save_control = CMOS_READ(RTC_CONTROL);
0248 spin_unlock_irqrestore(&rtc_lock, flags);
0249 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
0250 sec = bin2bcd(sec);
0251 min = bin2bcd(min);
0252 hrs = bin2bcd(hrs);
0253 day = bin2bcd(day);
0254 mon = bin2bcd(mon);
0255 yrs = bin2bcd(yrs);
0256 century = bin2bcd(century);
0257 }
0258
0259 spin_lock_irqsave(&rtc_lock, flags);
0260 save_control = CMOS_READ(RTC_CONTROL);
0261 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
0262 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
0263 if (apply_amd_register_a_behavior())
0264 CMOS_WRITE((save_freq_select & ~RTC_AMD_BANK_SELECT), RTC_FREQ_SELECT);
0265 else
0266 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
0267
0268 #ifdef CONFIG_MACH_DECSTATION
0269 CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
0270 #endif
0271 CMOS_WRITE(yrs, RTC_YEAR);
0272 CMOS_WRITE(mon, RTC_MONTH);
0273 CMOS_WRITE(day, RTC_DAY_OF_MONTH);
0274 CMOS_WRITE(hrs, RTC_HOURS);
0275 CMOS_WRITE(min, RTC_MINUTES);
0276 CMOS_WRITE(sec, RTC_SECONDS);
0277 #ifdef CONFIG_ACPI
0278 if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
0279 acpi_gbl_FADT.century)
0280 CMOS_WRITE(century, acpi_gbl_FADT.century);
0281 #endif
0282
0283 CMOS_WRITE(save_control, RTC_CONTROL);
0284 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
0285
0286 spin_unlock_irqrestore(&rtc_lock, flags);
0287
0288 return 0;
0289 }
0290 EXPORT_SYMBOL_GPL(mc146818_set_time);