1 /* 2 * Copyright 2007, François Revol, revol@free.fr. 3 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. All rights reserved. 4 * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de 5 * Copyright 2003, Jeff Ward, jeff@r2d2.stcloudstate.edu. All rights reserved. 6 * 7 * Distributed under the terms of the MIT License. 8 */ 9 10 #include <arch/real_time_clock.h> 11 12 #include <arch_platform.h> 13 #include <boot/kernel_args.h> 14 #include <real_time_clock.h> 15 #include <real_time_data.h> 16 #include <smp.h> 17 18 typedef struct { 19 uint8 second; 20 uint8 minute; 21 uint8 hour; 22 uint8 day; 23 uint8 month; 24 uint8 year; 25 uint8 century; 26 } cmos_time; 27 28 29 static uint32 30 bcd_to_int(uint8 bcd) 31 { 32 uint32 numl; 33 uint32 numh; 34 35 numl = bcd & 0x0f; 36 numh = (bcd & 0xf0) >> 4; 37 38 return numh * 10 + numl; 39 } 40 41 42 static uint8 43 int_to_bcd(uint32 number) 44 { 45 uint8 low; 46 uint8 high; 47 48 if (number > 99) 49 return 0; 50 51 high = number / 10; 52 low = number % 10; 53 54 return (high << 4) | low; 55 } 56 57 58 static int 59 same_time(const cmos_time *time1, const cmos_time *time2) 60 { 61 return time1->second == time2->second 62 && time1->minute == time2->minute 63 && time1->hour == time2->hour 64 && time1->day == time2->day 65 && time1->month == time2->month 66 && time1->year == time2->year 67 && time1->century == time2->century; 68 } 69 70 71 static uint8 72 cmos_read(uint8 addr) 73 { 74 return M68KPlatform::Default()->ReadRTCReg(addr); 75 } 76 77 78 static void 79 cmos_write(uint8 addr, uint8 data) 80 { 81 M68KPlatform::Default()->WriteRTCReg(addr, data); 82 } 83 84 85 static void 86 set_24_hour_mode(void) 87 { 88 uint8 status_b; 89 90 status_b = cmos_read(0x0b); 91 status_b |= 0x02; 92 cmos_write(0x0b, status_b); 93 } 94 95 96 static void 97 read_cmos_clock(cmos_time *cmos) 98 { 99 set_24_hour_mode(); 100 101 cmos->century = cmos_read(0x32); 102 cmos->year = cmos_read(0x09); 103 cmos->month = cmos_read(0x08); 104 cmos->day = cmos_read(0x07); 105 cmos->hour = cmos_read(0x04); 106 cmos->minute = cmos_read(0x02); 107 cmos->second = cmos_read(0x00); 108 } 109 110 111 static void 112 write_cmos_clock(cmos_time *cmos) 113 { 114 set_24_hour_mode(); 115 116 cmos_write(0x32, cmos->century); 117 cmos_write(0x09, cmos->year); 118 cmos_write(0x08, cmos->month); 119 cmos_write(0x07, cmos->day); 120 cmos_write(0x04, cmos->hour); 121 cmos_write(0x02, cmos->minute); 122 cmos_write(0x00, cmos->second); 123 } 124 125 126 static uint32 127 cmos_to_secs(const cmos_time *cmos) 128 { 129 struct tm t; 130 t.tm_year = bcd_to_int(cmos->century) * 100 + bcd_to_int(cmos->year) 131 - RTC_EPOCH_BASE_YEAR; 132 t.tm_mon = bcd_to_int(cmos->month) - 1; 133 t.tm_mday = bcd_to_int(cmos->day); 134 t.tm_hour = bcd_to_int(cmos->hour); 135 t.tm_min = bcd_to_int(cmos->minute); 136 t.tm_sec = bcd_to_int(cmos->second); 137 138 return rtc_tm_to_secs(&t); 139 } 140 141 142 static void 143 secs_to_cmos(uint32 seconds, cmos_time *cmos) 144 { 145 int wholeYear; 146 147 struct tm t; 148 rtc_secs_to_tm(seconds, &t); 149 150 wholeYear = t.tm_year + RTC_EPOCH_BASE_YEAR; 151 152 cmos->century = int_to_bcd(wholeYear / 100); 153 cmos->year = int_to_bcd(wholeYear % 100); 154 cmos->month = int_to_bcd(t.tm_mon + 1); 155 cmos->day = int_to_bcd(t.tm_mday); 156 cmos->hour = int_to_bcd(t.tm_hour); 157 cmos->minute = int_to_bcd(t.tm_min); 158 cmos->second = int_to_bcd(t.tm_sec); 159 } 160 161 162 // #pragma mark - 163 164 165 166 static spinlock sSetArchDataLock; 167 168 status_t 169 arch_rtc_init(kernel_args *args, struct real_time_data *data) 170 { 171 // init the platform RTC service 172 status_t error = M68KPlatform::Default()->InitRTC(args, data); 173 if (error != B_OK) 174 return error; 175 176 // init the arch specific part of the real_time_data 177 data->arch_data.data[0].system_time_offset = 0; 178 // cvFactor = 2^32 * 1000000 / tbFreq 179 // => (tb * cvFactor) >> 32 = (tb * 2^32 * 1000000 / tbFreq) >> 32 180 // = tb / tbFreq * 1000000 = time in us 181 data->arch_data.system_time_conversion_factor 182 = uint32((uint64(1) << 32) * 1000000 183 / args->arch_args.time_base_frequency); 184 data->arch_data.version = 0; 185 186 // init spinlock 187 B_INITIALIZE_SPINLOCK(&sSetArchDataLock); 188 189 // init system_time() conversion factor 190 __m68k_setup_system_time(&data->arch_data.system_time_conversion_factor); 191 192 return B_OK; 193 } 194 195 196 uint32 197 arch_rtc_get_hw_time(void) 198 { 199 return M68KPlatform::Default()->GetHardwareRTC(); 200 } 201 202 203 void 204 arch_rtc_set_hw_time(uint32 seconds) 205 { 206 M68KPlatform::Default()->SetHardwareRTC(seconds); 207 } 208 209 210 void 211 arch_rtc_set_system_time_offset(struct real_time_data *data, bigtime_t offset) 212 { 213 cpu_status state = disable_interrupts(); 214 acquire_spinlock(&sSetArchDataLock); 215 216 int32 version = data->arch_data.version + 1; 217 data->arch_data.data[version % 2].system_time_offset = offset; 218 data->arch_data.version = version; 219 220 release_spinlock(&sSetArchDataLock); 221 restore_interrupts(state); 222 } 223 224 225 bigtime_t 226 arch_rtc_get_system_time_offset(struct real_time_data *data) 227 { 228 int32 version; 229 bigtime_t offset; 230 do { 231 version = data->arch_data.version; 232 offset = data->arch_data.data[version % 2].system_time_offset; 233 } while (version != data->arch_data.version); 234 235 return offset; 236 } 237