- Factoring of auto.c
[coreboot.git] / src / pc80 / mc146818rtc_early.c
1 #include <pc80/mc146818rtc.h>
2 #include <part/fallback_boot.h>
3
4 static unsigned char cmos_read(unsigned char addr)
5 {
6         outb(addr, RTC_BASE_PORT + 0);
7         return inb(RTC_BASE_PORT + 1);
8 }
9
10 static void cmos_write(unsigned char val, unsigned char addr)
11 {
12         outb(addr, RTC_BASE_PORT + 0);
13         outb(val, RTC_BASE_PORT + 1);
14 }
15
16 static int cmos_error(void)
17 {
18         unsigned char reg_d;
19         /* See if the cmos error condition has been flagged */
20         reg_d = cmos_read(RTC_REG_D);
21         return (reg_d & RTC_VRT) == 0;
22 }
23
24 static int cmos_chksum_valid(void)
25 {
26         unsigned char addr;
27         unsigned long sum, old_sum;
28         sum = 0;
29         /* Comput the cmos checksum */
30         for(addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) {
31                 sum += cmos_read(addr);
32         }
33         sum = (sum & 0xffff) ^ 0xffff;
34
35         /* Read the stored checksum */
36         old_sum = cmos_read(LB_CKS_LOC) << 8;
37         old_sum |=  cmos_read(LB_CKS_LOC+1);
38
39         return sum == old_sum;
40 }
41
42
43 static int do_normal_boot(void)
44 {
45         unsigned char byte;
46
47         if (cmos_error() || !cmos_chksum_valid()) {
48                 unsigned char byte;
49                 /* There are no impossible values, no cheksums so just
50                  * trust whatever value we have in the the cmos,
51                  * but clear the fallback bit.
52                  */
53                 byte = cmos_read(RTC_BOOT_BYTE);
54                 byte &= 0x0c;
55                 byte |= MAX_REBOOT_CNT << 4;
56                 cmos_write(byte, RTC_BOOT_BYTE);
57         }
58
59         /* The RTC_BOOT_BYTE is now o.k. see where to go. */
60         byte = cmos_read(RTC_BOOT_BYTE);
61         
62         /* Are we in normal mode? */
63         if (byte & 1) {
64                 byte &= 0x0f; /* yes, clear the boot count */
65         }
66
67         /* Are we already at the max count? */
68         if ((byte >> 4) < MAX_REBOOT_CNT) {
69                 byte += 1 << 4; /* No, add 1 to the count */
70         }
71         else {
72                 byte &= 0xfc;   /* Yes, put in fallback mode */
73         }
74
75         /* Is this the first boot? */
76         if ((byte >> 4) <= 1) {
77                 byte = (byte & 0xfc) | ((byte & 1) << 1); /* yes, shift the boot bits */
78         }
79
80         /* Save the boot byte */
81         cmos_write(byte, RTC_BOOT_BYTE);
82
83         return ((byte >> 4) < MAX_REBOOT_CNT);
84 }