1 /* 2 * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de 3 * Copyright 2003, Jeff Ward, jeff@r2d2.stcloudstate.edu. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <arch/real_time_clock.h> 10 #include <arch/cpu.h> 11 #include <boot/kernel_args.h> 12 13 #include <real_time_clock.h> 14 #include <real_time_data.h> 15 16 17 #define CMOS_ADDR_PORT 0x70 18 #define CMOS_DATA_PORT 0x71 19 20 typedef struct { 21 uint8 second; 22 uint8 minute; 23 uint8 hour; 24 uint8 day; 25 uint8 month; 26 uint8 year; 27 uint8 century; 28 } cmos_time; 29 30 31 static uint32 32 bcd_to_int(uint8 bcd) 33 { 34 uint32 numl; 35 uint32 numh; 36 37 numl = bcd & 0x0f; 38 numh = (bcd & 0xf0) >> 4; 39 40 return numh * 10 + numl; 41 } 42 43 44 static uint8 45 int_to_bcd(uint32 number) 46 { 47 uint8 low; 48 uint8 high; 49 50 if (number > 99) 51 return 0; 52 53 high = number / 10; 54 low = number % 10; 55 56 return (high << 4) | low; 57 } 58 59 60 static int 61 same_time(const cmos_time *time1, const cmos_time *time2) 62 { 63 return time1->second == time2->second 64 && time1->minute == time2->minute 65 && time1->hour == time2->hour 66 && time1->day == time2->day 67 && time1->month == time2->month 68 && time1->year == time2->year 69 && time1->century == time2->century; 70 } 71 72 73 static uint8 74 cmos_read(uint8 addr) 75 { 76 int waitTime = 10000; 77 78 // Wait until bit 7 of Status Register A (indicating whether or not an update is in 79 // progress) is clear if we are reading one of the clock data registers... 80 if (addr < 0x0a) { 81 out8(0x0a, CMOS_ADDR_PORT); 82 while ((in8(CMOS_DATA_PORT) & 0x80) && --waitTime); 83 } 84 85 // then read the value. 86 out8(addr, CMOS_ADDR_PORT); 87 return in8(CMOS_DATA_PORT); 88 } 89 90 91 static void 92 cmos_write(uint8 addr, uint8 data) 93 { 94 out8(addr, CMOS_ADDR_PORT); 95 out8(data, CMOS_DATA_PORT); 96 } 97 98 99 static void 100 set_24_hour_mode(void) 101 { 102 uint8 status_b; 103 104 status_b = cmos_read(0x0b); 105 status_b |= 0x02; 106 cmos_write(0x0b, status_b); 107 } 108 109 110 static void 111 read_cmos_clock(cmos_time *cmos) 112 { 113 set_24_hour_mode(); 114 115 cmos->century = cmos_read(0x32); 116 cmos->year = cmos_read(0x09); 117 cmos->month = cmos_read(0x08); 118 cmos->day = cmos_read(0x07); 119 cmos->hour = cmos_read(0x04); 120 cmos->minute = cmos_read(0x02); 121 cmos->second = cmos_read(0x00); 122 } 123 124 125 static void 126 write_cmos_clock(cmos_time *cmos) 127 { 128 set_24_hour_mode(); 129 130 cmos_write(0x32, cmos->century); 131 cmos_write(0x09, cmos->year); 132 cmos_write(0x08, cmos->month); 133 cmos_write(0x07, cmos->day); 134 cmos_write(0x04, cmos->hour); 135 cmos_write(0x02, cmos->minute); 136 cmos_write(0x00, cmos->second); 137 } 138 139 140 static uint32 141 cmos_to_secs(const cmos_time *cmos) 142 { 143 struct tm t; 144 t.tm_year = bcd_to_int(cmos->century) * 100 + bcd_to_int(cmos->year) 145 - RTC_EPOCH_BASE_YEAR; 146 t.tm_mon = bcd_to_int(cmos->month) - 1; 147 t.tm_mday = bcd_to_int(cmos->day); 148 t.tm_hour = bcd_to_int(cmos->hour); 149 t.tm_min = bcd_to_int(cmos->minute); 150 t.tm_sec = bcd_to_int(cmos->second); 151 152 return rtc_tm_to_secs(&t); 153 } 154 155 156 static void 157 secs_to_cmos(uint32 seconds, cmos_time *cmos) 158 { 159 int wholeYear; 160 161 struct tm t; 162 rtc_secs_to_tm(seconds, &t); 163 164 wholeYear = t.tm_year + RTC_EPOCH_BASE_YEAR; 165 166 cmos->century = int_to_bcd(wholeYear / 100); 167 cmos->year = int_to_bcd(wholeYear % 100); 168 cmos->month = int_to_bcd(t.tm_mon + 1); 169 cmos->day = int_to_bcd(t.tm_mday); 170 cmos->hour = int_to_bcd(t.tm_hour); 171 cmos->minute = int_to_bcd(t.tm_min); 172 cmos->second = int_to_bcd(t.tm_sec); 173 } 174 175 176 // #pragma mark - 177 178 179 status_t 180 arch_rtc_init(struct kernel_args *args, struct real_time_data *data) 181 { 182 data->arch_data.system_time_conversion_factor 183 = args->arch_args.system_time_cv_factor; 184 return B_OK; 185 } 186 187 188 uint32 189 arch_rtc_get_hw_time(void) 190 { 191 int waitTime; 192 cmos_time cmos1; 193 cmos_time cmos2; 194 195 waitTime = 1000; 196 197 // We will read the clock twice and make sure both reads are equal. This will prevent 198 // problems that would occur if the clock is read during an update (e.g. if we read the hour 199 // at 8:59:59, the clock gets changed, and then we read the minute and second, we would 200 // be off by a whole hour) 201 do { 202 read_cmos_clock(&cmos1); 203 read_cmos_clock(&cmos2); 204 } while (!same_time(&cmos1, &cmos2) && --waitTime); 205 206 // Convert the CMOS data to seconds since 1970. 207 return cmos_to_secs(&cmos1); 208 } 209 210 211 void 212 arch_rtc_set_hw_time(uint32 seconds) 213 { 214 cmos_time cmos; 215 216 secs_to_cmos(seconds, &cmos); 217 write_cmos_clock(&cmos); 218 } 219 220 221 void 222 arch_rtc_set_system_time_offset(struct real_time_data *data, bigtime_t offset) 223 { 224 atomic_set64(&data->arch_data.system_time_offset, offset); 225 } 226 227 228 bigtime_t 229 arch_rtc_get_system_time_offset(struct real_time_data *data) 230 { 231 return atomic_get64(&data->arch_data.system_time_offset); 232 } 233