blob: 0652f27c47ff5967eb4a270e8fc37de4b2775b22 [file] [log] [blame]
Stefan Reinauerea5c2b62011-10-27 18:42:53 +02001#include <stdint.h>
Eric Biederman05f26fc2003-06-11 21:55:00 +00002#include <pc80/mc146818rtc.h>
Stefan Reinauerde3206a2010-02-22 06:09:43 +00003#include <fallback.h>
Stefan Reinauer10ec0fe2010-09-25 10:40:47 +00004#if CONFIG_USE_OPTION_TABLE
5#include "option_table.h"
6#endif
Eric Biederman05f26fc2003-06-11 21:55:00 +00007
Stefan Reinauer08670622009-06-30 15:17:49 +00008#ifndef CONFIG_MAX_REBOOT_CNT
9#error "CONFIG_MAX_REBOOT_CNT not defined"
Eric Biederman8d9c1232003-06-17 08:42:17 +000010#endif
Stefan Reinauer08670622009-06-30 15:17:49 +000011#if CONFIG_MAX_REBOOT_CNT > 15
12#error "CONFIG_MAX_REBOOT_CNT too high"
Eric Biederman8d9c1232003-06-17 08:42:17 +000013#endif
14
Eric Biederman05f26fc2003-06-11 21:55:00 +000015static int cmos_error(void)
16{
17 unsigned char reg_d;
18 /* See if the cmos error condition has been flagged */
19 reg_d = cmos_read(RTC_REG_D);
20 return (reg_d & RTC_VRT) == 0;
21}
22
23static int cmos_chksum_valid(void)
24{
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000025#if CONFIG_USE_OPTION_TABLE
Eric Biederman05f26fc2003-06-11 21:55:00 +000026 unsigned char addr;
Stefan Reinauerea5c2b62011-10-27 18:42:53 +020027 u16 sum, old_sum;
Eric Biederman05f26fc2003-06-11 21:55:00 +000028 sum = 0;
Stefan Reinauerea5c2b62011-10-27 18:42:53 +020029 /* Compute the cmos checksum */
Stefan Reinauerb5828d72010-03-29 17:14:28 +000030 for(addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) {
Eric Biederman05f26fc2003-06-11 21:55:00 +000031 sum += cmos_read(addr);
32 }
Eric Biederman05f26fc2003-06-11 21:55:00 +000033
34 /* Read the stored checksum */
Stefan Reinauerb5828d72010-03-29 17:14:28 +000035 old_sum = cmos_read(LB_CKS_LOC) << 8;
36 old_sum |= cmos_read(LB_CKS_LOC+1);
Eric Biederman05f26fc2003-06-11 21:55:00 +000037
38 return sum == old_sum;
Stefan Reinauer8e726b72010-03-29 23:01:35 +000039#else
40 return 0;
41#endif
Eric Biederman05f26fc2003-06-11 21:55:00 +000042}
43
44
Stefan Reinauer53b0ea42010-03-22 11:50:52 +000045static inline int last_boot_normal(void)
Eric Biederman9b4336c2003-07-19 04:28:22 +000046{
47 unsigned char byte;
48 byte = cmos_read(RTC_BOOT_BYTE);
49 return (byte & (1 << 1));
50}
51
Stefan Reinauer53b0ea42010-03-22 11:50:52 +000052static inline int do_normal_boot(void)
Eric Biederman05f26fc2003-06-11 21:55:00 +000053{
54 unsigned char byte;
55
56 if (cmos_error() || !cmos_chksum_valid()) {
Stefan Reinauerf96c2d92009-04-22 16:23:47 +000057 /* There are no impossible values, no checksums so just
Eric Biederman05f26fc2003-06-11 21:55:00 +000058 * trust whatever value we have in the the cmos,
59 * but clear the fallback bit.
60 */
61 byte = cmos_read(RTC_BOOT_BYTE);
62 byte &= 0x0c;
Stefan Reinauer08670622009-06-30 15:17:49 +000063 byte |= CONFIG_MAX_REBOOT_CNT << 4;
Eric Biederman05f26fc2003-06-11 21:55:00 +000064 cmos_write(byte, RTC_BOOT_BYTE);
65 }
66
67 /* The RTC_BOOT_BYTE is now o.k. see where to go. */
68 byte = cmos_read(RTC_BOOT_BYTE);
Stefan Reinauer14e22772010-04-27 06:56:47 +000069
Eric Biederman05f26fc2003-06-11 21:55:00 +000070 /* Are we in normal mode? */
71 if (byte & 1) {
72 byte &= 0x0f; /* yes, clear the boot count */
73 }
74
Eric Biederman2c018fb2003-07-21 20:13:45 +000075 /* Properly set the last boot flag */
76 byte &= 0xfc;
Stefan Reinauer08670622009-06-30 15:17:49 +000077 if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
Eric Biederman2c018fb2003-07-21 20:13:45 +000078 byte |= (1<<1);
79 }
80
Eric Biederman05f26fc2003-06-11 21:55:00 +000081 /* Are we already at the max count? */
Stefan Reinauer08670622009-06-30 15:17:49 +000082 if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
Eric Biederman05f26fc2003-06-11 21:55:00 +000083 byte += 1 << 4; /* No, add 1 to the count */
84 }
85 else {
86 byte &= 0xfc; /* Yes, put in fallback mode */
87 }
88
Eric Biederman05f26fc2003-06-11 21:55:00 +000089 /* Save the boot byte */
90 cmos_write(byte, RTC_BOOT_BYTE);
91
Eric Biederman2c018fb2003-07-21 20:13:45 +000092 return (byte & (1<<1));
Eric Biederman05f26fc2003-06-11 21:55:00 +000093}
Eric Biederman5cd81732004-03-11 15:01:31 +000094
Patrick Georgib2517532011-05-10 21:53:13 +000095unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def)
Eric Biederman5cd81732004-03-11 15:01:31 +000096{
Edwin Beasanteb50c7d2010-07-06 21:05:04 +000097#if CONFIG_USE_OPTION_TABLE
Eric Biederman5cd81732004-03-11 15:01:31 +000098 unsigned byte;
99 byte = cmos_read(start/8);
100 return (byte >> (start & 7U)) & ((1U << size) - 1U);
101#else
102 return def;
103#endif
104}