blob: fa1f388804b5ac0812827eee607ae3f5946ff695 [file] [log] [blame]
Eric Biederman05f26fc2003-06-11 21:55:00 +00001#include <pc80/mc146818rtc.h>
Stefan Reinauerde3206a2010-02-22 06:09:43 +00002#include <fallback.h>
Stefan Reinauer8e726b72010-03-29 23:01:35 +00003#if CONFIG_HAVE_OPTION_TABLE
4#include <option_table.h>
5#endif
Eric Biederman05f26fc2003-06-11 21:55:00 +00006
Stefan Reinauer08670622009-06-30 15:17:49 +00007#ifndef CONFIG_MAX_REBOOT_CNT
8#error "CONFIG_MAX_REBOOT_CNT not defined"
Eric Biederman8d9c1232003-06-17 08:42:17 +00009#endif
Stefan Reinauer08670622009-06-30 15:17:49 +000010#if CONFIG_MAX_REBOOT_CNT > 15
11#error "CONFIG_MAX_REBOOT_CNT too high"
Eric Biederman8d9c1232003-06-17 08:42:17 +000012#endif
13
Eric Biederman05f26fc2003-06-11 21:55:00 +000014static unsigned char cmos_read(unsigned char addr)
15{
Stefan Reinauer73d5daa2009-04-22 09:03:08 +000016 int offs = 0;
17 if (addr >= 128) {
18 offs = 2;
19 addr -= 128;
20 }
21 outb(addr, RTC_BASE_PORT + offs + 0);
22 return inb(RTC_BASE_PORT + offs + 1);
Eric Biederman05f26fc2003-06-11 21:55:00 +000023}
24
25static void cmos_write(unsigned char val, unsigned char addr)
26{
Stefan Reinauer73d5daa2009-04-22 09:03:08 +000027 int offs = 0;
28 if (addr >= 128) {
29 offs = 2;
30 addr -= 128;
31 }
32 outb(addr, RTC_BASE_PORT + offs + 0);
33 outb(val, RTC_BASE_PORT + offs + 1);
Eric Biederman05f26fc2003-06-11 21:55:00 +000034}
35
36static int cmos_error(void)
37{
38 unsigned char reg_d;
39 /* See if the cmos error condition has been flagged */
40 reg_d = cmos_read(RTC_REG_D);
41 return (reg_d & RTC_VRT) == 0;
42}
43
44static int cmos_chksum_valid(void)
45{
Stefan Reinauer8e726b72010-03-29 23:01:35 +000046#if CONFIG_HAVE_OPTION_TABLE == 1
Eric Biederman05f26fc2003-06-11 21:55:00 +000047 unsigned char addr;
48 unsigned long sum, old_sum;
49 sum = 0;
50 /* Comput the cmos checksum */
Stefan Reinauerb5828d72010-03-29 17:14:28 +000051 for(addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) {
Eric Biederman05f26fc2003-06-11 21:55:00 +000052 sum += cmos_read(addr);
53 }
54 sum = (sum & 0xffff) ^ 0xffff;
55
56 /* Read the stored checksum */
Stefan Reinauerb5828d72010-03-29 17:14:28 +000057 old_sum = cmos_read(LB_CKS_LOC) << 8;
58 old_sum |= cmos_read(LB_CKS_LOC+1);
Eric Biederman05f26fc2003-06-11 21:55:00 +000059
60 return sum == old_sum;
Stefan Reinauer8e726b72010-03-29 23:01:35 +000061#else
62 return 0;
63#endif
Eric Biederman05f26fc2003-06-11 21:55:00 +000064}
65
66
Stefan Reinauer53b0ea42010-03-22 11:50:52 +000067static inline int last_boot_normal(void)
Eric Biederman9b4336c2003-07-19 04:28:22 +000068{
69 unsigned char byte;
70 byte = cmos_read(RTC_BOOT_BYTE);
71 return (byte & (1 << 1));
72}
73
Stefan Reinauer53b0ea42010-03-22 11:50:52 +000074static inline int do_normal_boot(void)
Eric Biederman05f26fc2003-06-11 21:55:00 +000075{
76 unsigned char byte;
77
78 if (cmos_error() || !cmos_chksum_valid()) {
Stefan Reinauerf96c2d92009-04-22 16:23:47 +000079 /* There are no impossible values, no checksums so just
Eric Biederman05f26fc2003-06-11 21:55:00 +000080 * trust whatever value we have in the the cmos,
81 * but clear the fallback bit.
82 */
83 byte = cmos_read(RTC_BOOT_BYTE);
84 byte &= 0x0c;
Stefan Reinauer08670622009-06-30 15:17:49 +000085 byte |= CONFIG_MAX_REBOOT_CNT << 4;
Eric Biederman05f26fc2003-06-11 21:55:00 +000086 cmos_write(byte, RTC_BOOT_BYTE);
87 }
88
89 /* The RTC_BOOT_BYTE is now o.k. see where to go. */
90 byte = cmos_read(RTC_BOOT_BYTE);
Stefan Reinauer14e22772010-04-27 06:56:47 +000091
Eric Biederman05f26fc2003-06-11 21:55:00 +000092 /* Are we in normal mode? */
93 if (byte & 1) {
94 byte &= 0x0f; /* yes, clear the boot count */
95 }
96
Eric Biederman2c018fb2003-07-21 20:13:45 +000097 /* Properly set the last boot flag */
98 byte &= 0xfc;
Stefan Reinauer08670622009-06-30 15:17:49 +000099 if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
Eric Biederman2c018fb2003-07-21 20:13:45 +0000100 byte |= (1<<1);
101 }
102
Eric Biederman05f26fc2003-06-11 21:55:00 +0000103 /* Are we already at the max count? */
Stefan Reinauer08670622009-06-30 15:17:49 +0000104 if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
Eric Biederman05f26fc2003-06-11 21:55:00 +0000105 byte += 1 << 4; /* No, add 1 to the count */
106 }
107 else {
108 byte &= 0xfc; /* Yes, put in fallback mode */
109 }
110
Eric Biederman05f26fc2003-06-11 21:55:00 +0000111 /* Save the boot byte */
112 cmos_write(byte, RTC_BOOT_BYTE);
113
Eric Biederman2c018fb2003-07-21 20:13:45 +0000114 return (byte & (1<<1));
Eric Biederman05f26fc2003-06-11 21:55:00 +0000115}
Eric Biederman5cd81732004-03-11 15:01:31 +0000116
Stefan Reinauer53b0ea42010-03-22 11:50:52 +0000117static inline unsigned read_option(unsigned start, unsigned size, unsigned def)
Eric Biederman5cd81732004-03-11 15:01:31 +0000118{
Stefan Reinauer08670622009-06-30 15:17:49 +0000119#if CONFIG_USE_OPTION_TABLE == 1
Eric Biederman5cd81732004-03-11 15:01:31 +0000120 unsigned byte;
121 byte = cmos_read(start/8);
122 return (byte >> (start & 7U)) & ((1U << size) - 1U);
123#else
124 return def;
125#endif
126}