rtc-mc146818-lib.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/bcd.h>
  3. #include <linux/delay.h>
  4. #include <linux/export.h>
  5. #include <linux/mc146818rtc.h>
  6. #ifdef CONFIG_ACPI
  7. #include <linux/acpi.h>
  8. #endif
  9. #define UIP_RECHECK_DELAY 100 /* usec */
  10. #define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
  11. #define UIP_RECHECK_LOOPS_MS(x) (x / UIP_RECHECK_DELAY_MS)
  12. /*
  13. * Execute a function while the UIP (Update-in-progress) bit of the RTC is
  14. * unset. The timeout is configurable by the caller in ms.
  15. *
  16. * Warning: callback may be executed more then once.
  17. */
  18. bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
  19. int timeout,
  20. void *param)
  21. {
  22. int i;
  23. unsigned long flags;
  24. unsigned char seconds;
  25. for (i = 0; UIP_RECHECK_LOOPS_MS(i) < timeout; i++) {
  26. spin_lock_irqsave(&rtc_lock, flags);
  27. /*
  28. * Check whether there is an update in progress during which the
  29. * readout is unspecified. The maximum update time is ~2ms. Poll
  30. * for completion.
  31. *
  32. * Store the second value before checking UIP so a long lasting
  33. * NMI which happens to hit after the UIP check cannot make
  34. * an update cycle invisible.
  35. */
  36. seconds = CMOS_READ(RTC_SECONDS);
  37. if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
  38. spin_unlock_irqrestore(&rtc_lock, flags);
  39. udelay(UIP_RECHECK_DELAY);
  40. continue;
  41. }
  42. /* Revalidate the above readout */
  43. if (seconds != CMOS_READ(RTC_SECONDS)) {
  44. spin_unlock_irqrestore(&rtc_lock, flags);
  45. continue;
  46. }
  47. if (callback)
  48. callback(seconds, param);
  49. /*
  50. * Check for the UIP bit again. If it is set now then
  51. * the above values may contain garbage.
  52. */
  53. if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
  54. spin_unlock_irqrestore(&rtc_lock, flags);
  55. udelay(UIP_RECHECK_DELAY);
  56. continue;
  57. }
  58. /*
  59. * A NMI might have interrupted the above sequence so check
  60. * whether the seconds value has changed which indicates that
  61. * the NMI took longer than the UIP bit was set. Unlikely, but
  62. * possible and there is also virt...
  63. */
  64. if (seconds != CMOS_READ(RTC_SECONDS)) {
  65. spin_unlock_irqrestore(&rtc_lock, flags);
  66. continue;
  67. }
  68. spin_unlock_irqrestore(&rtc_lock, flags);
  69. if (UIP_RECHECK_LOOPS_MS(i) >= 100)
  70. pr_warn("Reading current time from RTC took around %li ms\n",
  71. UIP_RECHECK_LOOPS_MS(i));
  72. return true;
  73. }
  74. return false;
  75. }
  76. EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
  77. /*
  78. * If the UIP (Update-in-progress) bit of the RTC is set for more then
  79. * 10ms, the RTC is apparently broken or not present.
  80. */
  81. bool mc146818_does_rtc_work(void)
  82. {
  83. return mc146818_avoid_UIP(NULL, 1000, NULL);
  84. }
  85. EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
  86. struct mc146818_get_time_callback_param {
  87. struct rtc_time *time;
  88. unsigned char ctrl;
  89. #ifdef CONFIG_ACPI
  90. unsigned char century;
  91. #endif
  92. #ifdef CONFIG_MACH_DECSTATION
  93. unsigned int real_year;
  94. #endif
  95. };
  96. static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
  97. {
  98. struct mc146818_get_time_callback_param *p = param_in;
  99. /*
  100. * Only the values that we read from the RTC are set. We leave
  101. * tm_wday, tm_yday and tm_isdst untouched. Even though the
  102. * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
  103. * by the RTC when initially set to a non-zero value.
  104. */
  105. p->time->tm_sec = seconds;
  106. p->time->tm_min = CMOS_READ(RTC_MINUTES);
  107. p->time->tm_hour = CMOS_READ(RTC_HOURS);
  108. p->time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
  109. p->time->tm_mon = CMOS_READ(RTC_MONTH);
  110. p->time->tm_year = CMOS_READ(RTC_YEAR);
  111. #ifdef CONFIG_MACH_DECSTATION
  112. p->real_year = CMOS_READ(RTC_DEC_YEAR);
  113. #endif
  114. #ifdef CONFIG_ACPI
  115. if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
  116. acpi_gbl_FADT.century) {
  117. p->century = CMOS_READ(acpi_gbl_FADT.century);
  118. } else {
  119. p->century = 0;
  120. }
  121. #endif
  122. p->ctrl = CMOS_READ(RTC_CONTROL);
  123. }
  124. /**
  125. * mc146818_get_time - Get the current time from the RTC
  126. * @time: pointer to struct rtc_time to store the current time
  127. * @timeout: timeout value in ms
  128. *
  129. * This function reads the current time from the RTC and stores it in the
  130. * provided struct rtc_time. The timeout parameter specifies the maximum
  131. * time to wait for the RTC to become ready.
  132. *
  133. * Return: 0 on success, -ETIMEDOUT if the RTC did not become ready within
  134. * the specified timeout, or another error code if an error occurred.
  135. */
  136. int mc146818_get_time(struct rtc_time *time, int timeout)
  137. {
  138. struct mc146818_get_time_callback_param p = {
  139. .time = time
  140. };
  141. if (!mc146818_avoid_UIP(mc146818_get_time_callback, timeout, &p)) {
  142. memset(time, 0, sizeof(*time));
  143. return -ETIMEDOUT;
  144. }
  145. if (!(p.ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  146. {
  147. time->tm_sec = bcd2bin(time->tm_sec);
  148. time->tm_min = bcd2bin(time->tm_min);
  149. time->tm_hour = bcd2bin(time->tm_hour);
  150. time->tm_mday = bcd2bin(time->tm_mday);
  151. time->tm_mon = bcd2bin(time->tm_mon);
  152. time->tm_year = bcd2bin(time->tm_year);
  153. #ifdef CONFIG_ACPI
  154. p.century = bcd2bin(p.century);
  155. #endif
  156. }
  157. #ifdef CONFIG_MACH_DECSTATION
  158. time->tm_year += p.real_year - 72;
  159. #endif
  160. #ifdef CONFIG_ACPI
  161. if (p.century > 19)
  162. time->tm_year += (p.century - 19) * 100;
  163. #endif
  164. /*
  165. * Account for differences between how the RTC uses the values
  166. * and how they are defined in a struct rtc_time;
  167. */
  168. if (time->tm_year <= 69)
  169. time->tm_year += 100;
  170. time->tm_mon--;
  171. return 0;
  172. }
  173. EXPORT_SYMBOL_GPL(mc146818_get_time);
  174. /* AMD systems don't allow access to AltCentury with DV1 */
  175. static bool apply_amd_register_a_behavior(void)
  176. {
  177. #ifdef CONFIG_X86
  178. if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
  179. boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
  180. return true;
  181. #endif
  182. return false;
  183. }
  184. /* Set the current date and time in the real time clock. */
  185. int mc146818_set_time(struct rtc_time *time)
  186. {
  187. unsigned long flags;
  188. unsigned char mon, day, hrs, min, sec;
  189. unsigned char save_control, save_freq_select;
  190. unsigned int yrs;
  191. #ifdef CONFIG_MACH_DECSTATION
  192. unsigned int real_yrs;
  193. #endif
  194. unsigned char century = 0;
  195. yrs = time->tm_year;
  196. mon = time->tm_mon + 1; /* tm_mon starts at zero */
  197. day = time->tm_mday;
  198. hrs = time->tm_hour;
  199. min = time->tm_min;
  200. sec = time->tm_sec;
  201. if (yrs > 255) /* They are unsigned */
  202. return -EINVAL;
  203. #ifdef CONFIG_MACH_DECSTATION
  204. real_yrs = yrs;
  205. yrs = 72;
  206. /*
  207. * We want to keep the year set to 73 until March
  208. * for non-leap years, so that Feb, 29th is handled
  209. * correctly.
  210. */
  211. if (!is_leap_year(real_yrs + 1900) && mon < 3) {
  212. real_yrs--;
  213. yrs = 73;
  214. }
  215. #endif
  216. #ifdef CONFIG_ACPI
  217. if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
  218. acpi_gbl_FADT.century) {
  219. century = (yrs + 1900) / 100;
  220. yrs %= 100;
  221. }
  222. #endif
  223. /* These limits and adjustments are independent of
  224. * whether the chip is in binary mode or not.
  225. */
  226. if (yrs > 169)
  227. return -EINVAL;
  228. if (yrs >= 100)
  229. yrs -= 100;
  230. spin_lock_irqsave(&rtc_lock, flags);
  231. save_control = CMOS_READ(RTC_CONTROL);
  232. spin_unlock_irqrestore(&rtc_lock, flags);
  233. if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
  234. sec = bin2bcd(sec);
  235. min = bin2bcd(min);
  236. hrs = bin2bcd(hrs);
  237. day = bin2bcd(day);
  238. mon = bin2bcd(mon);
  239. yrs = bin2bcd(yrs);
  240. century = bin2bcd(century);
  241. }
  242. spin_lock_irqsave(&rtc_lock, flags);
  243. save_control = CMOS_READ(RTC_CONTROL);
  244. CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
  245. save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
  246. if (apply_amd_register_a_behavior())
  247. CMOS_WRITE((save_freq_select & ~RTC_AMD_BANK_SELECT), RTC_FREQ_SELECT);
  248. else
  249. CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
  250. #ifdef CONFIG_MACH_DECSTATION
  251. CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
  252. #endif
  253. CMOS_WRITE(yrs, RTC_YEAR);
  254. CMOS_WRITE(mon, RTC_MONTH);
  255. CMOS_WRITE(day, RTC_DAY_OF_MONTH);
  256. CMOS_WRITE(hrs, RTC_HOURS);
  257. CMOS_WRITE(min, RTC_MINUTES);
  258. CMOS_WRITE(sec, RTC_SECONDS);
  259. #ifdef CONFIG_ACPI
  260. if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
  261. acpi_gbl_FADT.century)
  262. CMOS_WRITE(century, acpi_gbl_FADT.century);
  263. #endif
  264. CMOS_WRITE(save_control, RTC_CONTROL);
  265. CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
  266. spin_unlock_irqrestore(&rtc_lock, flags);
  267. return 0;
  268. }
  269. EXPORT_SYMBOL_GPL(mc146818_set_time);