1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2001 4 * Denis Peter MPL AG Switzerland. d.peter@mpl.ch 5 */ 6 7 /* 8 * Date & Time support for the MC146818 (PIXX4) RTC 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <dm.h> 14 #include <rtc.h> 15 16 #if defined(CONFIG_X86) || defined(CONFIG_MALTA) 17 #include <asm/io.h> 18 #define in8(p) inb(p) 19 #define out8(p, v) outb(v, p) 20 #endif 21 22 #if defined(CONFIG_CMD_DATE) 23 24 /* Set this to 1 to clear the CMOS RAM */ 25 #define CLEAR_CMOS 0 26 27 #define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70 28 #define RTC_SECONDS 0x00 29 #define RTC_SECONDS_ALARM 0x01 30 #define RTC_MINUTES 0x02 31 #define RTC_MINUTES_ALARM 0x03 32 #define RTC_HOURS 0x04 33 #define RTC_HOURS_ALARM 0x05 34 #define RTC_DAY_OF_WEEK 0x06 35 #define RTC_DATE_OF_MONTH 0x07 36 #define RTC_MONTH 0x08 37 #define RTC_YEAR 0x09 38 #define RTC_CONFIG_A 0x0a 39 #define RTC_CONFIG_B 0x0b 40 #define RTC_CONFIG_C 0x0c 41 #define RTC_CONFIG_D 0x0d 42 #define RTC_REG_SIZE 0x80 43 44 #define RTC_CONFIG_A_REF_CLCK_32KHZ (1 << 5) 45 #define RTC_CONFIG_A_RATE_1024HZ 6 46 47 #define RTC_CONFIG_B_24H (1 << 1) 48 49 #define RTC_CONFIG_D_VALID_RAM_AND_TIME 0x80 50 51 static int mc146818_read8(int reg) 52 { 53 #ifdef CONFIG_SYS_RTC_REG_BASE_ADDR 54 return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg); 55 #else 56 int ofs = 0; 57 58 if (reg >= 128) { 59 ofs = 2; 60 reg -= 128; 61 } 62 out8(RTC_PORT_MC146818 + ofs, reg); 63 64 return in8(RTC_PORT_MC146818 + ofs + 1); 65 #endif 66 } 67 68 static void mc146818_write8(int reg, uchar val) 69 { 70 #ifdef CONFIG_SYS_RTC_REG_BASE_ADDR 71 out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val); 72 #else 73 int ofs = 0; 74 75 if (reg >= 128) { 76 ofs = 2; 77 reg -= 128; 78 } 79 out8(RTC_PORT_MC146818 + ofs, reg); 80 out8(RTC_PORT_MC146818 + ofs + 1, val); 81 #endif 82 } 83 84 static int mc146818_get(struct rtc_time *tmp) 85 { 86 uchar sec, min, hour, mday, wday __attribute__((unused)),mon, year; 87 88 /* here check if rtc can be accessed */ 89 while ((mc146818_read8(RTC_CONFIG_A) & 0x80) == 0x80) 90 ; 91 92 sec = mc146818_read8(RTC_SECONDS); 93 min = mc146818_read8(RTC_MINUTES); 94 hour = mc146818_read8(RTC_HOURS); 95 mday = mc146818_read8(RTC_DATE_OF_MONTH); 96 wday = mc146818_read8(RTC_DAY_OF_WEEK); 97 mon = mc146818_read8(RTC_MONTH); 98 year = mc146818_read8(RTC_YEAR); 99 #ifdef RTC_DEBUG 100 printf("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x hr: %02x min: %02x sec: %02x\n", 101 year, mon, mday, wday, hour, min, sec); 102 printf("Alarms: mday: %02x hour: %02x min: %02x sec: %02x\n", 103 mc146818_read8(RTC_CONFIG_D) & 0x3f, 104 mc146818_read8(RTC_HOURS_ALARM), 105 mc146818_read8(RTC_MINUTES_ALARM), 106 mc146818_read8(RTC_SECONDS_ALARM)); 107 #endif 108 tmp->tm_sec = bcd2bin(sec & 0x7f); 109 tmp->tm_min = bcd2bin(min & 0x7f); 110 tmp->tm_hour = bcd2bin(hour & 0x3f); 111 tmp->tm_mday = bcd2bin(mday & 0x3f); 112 tmp->tm_mon = bcd2bin(mon & 0x1f); 113 tmp->tm_year = bcd2bin(year); 114 115 if (tmp->tm_year < 70) 116 tmp->tm_year += 2000; 117 else 118 tmp->tm_year += 1900; 119 120 tmp->tm_yday = 0; 121 tmp->tm_isdst = 0; 122 /* 123 * The mc146818 only updates wday if it is non-zero, sunday is 1 124 * saturday is 7. So let's use our library routine. 125 */ 126 rtc_calc_weekday(tmp); 127 #ifdef RTC_DEBUG 128 printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 129 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 130 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 131 #endif 132 133 return 0; 134 } 135 136 static int mc146818_set(struct rtc_time *tmp) 137 { 138 #ifdef RTC_DEBUG 139 printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 140 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 141 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 142 #endif 143 /* Disable the RTC to update the regs */ 144 mc146818_write8(RTC_CONFIG_B, 0x82); 145 146 mc146818_write8(RTC_YEAR, bin2bcd(tmp->tm_year % 100)); 147 mc146818_write8(RTC_MONTH, bin2bcd(tmp->tm_mon)); 148 /* Sunday = 1, Saturday = 7 */ 149 mc146818_write8(RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday + 1)); 150 mc146818_write8(RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday)); 151 mc146818_write8(RTC_HOURS, bin2bcd(tmp->tm_hour)); 152 mc146818_write8(RTC_MINUTES, bin2bcd(tmp->tm_min)); 153 mc146818_write8(RTC_SECONDS, bin2bcd(tmp->tm_sec)); 154 155 /* Enable the RTC to update the regs */ 156 mc146818_write8(RTC_CONFIG_B, 0x02); 157 158 return 0; 159 } 160 161 static void mc146818_reset(void) 162 { 163 /* Disable the RTC to update the regs */ 164 mc146818_write8(RTC_CONFIG_B, 0x82); 165 166 /* Normal OP */ 167 mc146818_write8(RTC_CONFIG_A, 0x20); 168 mc146818_write8(RTC_CONFIG_B, 0x00); 169 mc146818_write8(RTC_CONFIG_B, 0x00); 170 171 /* Enable the RTC to update the regs */ 172 mc146818_write8(RTC_CONFIG_B, 0x02); 173 } 174 175 static void mc146818_init(void) 176 { 177 #if CLEAR_CMOS 178 int i; 179 180 rtc_write8(RTC_SECONDS_ALARM, 0); 181 rtc_write8(RTC_MINUTES_ALARM, 0); 182 rtc_write8(RTC_HOURS_ALARM, 0); 183 for (i = RTC_CONFIG_A; i < RTC_REG_SIZE; i++) 184 rtc_write8(i, 0); 185 printf("RTC: zeroing CMOS RAM\n"); 186 #endif 187 188 /* Setup the real time clock */ 189 mc146818_write8(RTC_CONFIG_B, RTC_CONFIG_B_24H); 190 /* Setup the frequency it operates at */ 191 mc146818_write8(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ | 192 RTC_CONFIG_A_RATE_1024HZ); 193 /* Ensure all reserved bits are 0 in register D */ 194 mc146818_write8(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME); 195 196 /* Clear any pending interrupts */ 197 mc146818_read8(RTC_CONFIG_C); 198 } 199 #endif /* CONFIG_CMD_DATE */ 200 201 #ifdef CONFIG_DM_RTC 202 203 static int rtc_mc146818_get(struct udevice *dev, struct rtc_time *time) 204 { 205 return mc146818_get(time); 206 } 207 208 static int rtc_mc146818_set(struct udevice *dev, const struct rtc_time *time) 209 { 210 return mc146818_set((struct rtc_time *)time); 211 } 212 213 static int rtc_mc146818_reset(struct udevice *dev) 214 { 215 mc146818_reset(); 216 217 return 0; 218 } 219 220 static int rtc_mc146818_read8(struct udevice *dev, unsigned int reg) 221 { 222 return mc146818_read8(reg); 223 } 224 225 static int rtc_mc146818_write8(struct udevice *dev, unsigned int reg, int val) 226 { 227 mc146818_write8(reg, val); 228 229 return 0; 230 } 231 232 static int rtc_mc146818_probe(struct udevice *dev) 233 { 234 mc146818_init(); 235 236 return 0; 237 } 238 239 static const struct rtc_ops rtc_mc146818_ops = { 240 .get = rtc_mc146818_get, 241 .set = rtc_mc146818_set, 242 .reset = rtc_mc146818_reset, 243 .read8 = rtc_mc146818_read8, 244 .write8 = rtc_mc146818_write8, 245 }; 246 247 static const struct udevice_id rtc_mc146818_ids[] = { 248 { .compatible = "motorola,mc146818" }, 249 { } 250 }; 251 252 U_BOOT_DRIVER(rtc_mc146818) = { 253 .name = "rtc_mc146818", 254 .id = UCLASS_RTC, 255 .of_match = rtc_mc146818_ids, 256 .probe = rtc_mc146818_probe, 257 .ops = &rtc_mc146818_ops, 258 }; 259 260 #else /* !CONFIG_DM_RTC */ 261 262 int rtc_get(struct rtc_time *tmp) 263 { 264 return mc146818_get(tmp); 265 } 266 267 int rtc_set(struct rtc_time *tmp) 268 { 269 return mc146818_set(tmp); 270 } 271 272 void rtc_reset(void) 273 { 274 mc146818_reset(); 275 } 276 277 int rtc_read8(int reg) 278 { 279 return mc146818_read8(reg); 280 } 281 282 void rtc_write8(int reg, uchar val) 283 { 284 mc146818_write8(reg, val); 285 } 286 287 u32 rtc_read32(int reg) 288 { 289 u32 value = 0; 290 int i; 291 292 for (i = 0; i < sizeof(value); i++) 293 value |= rtc_read8(reg + i) << (i << 3); 294 295 return value; 296 } 297 298 void rtc_write32(int reg, u32 value) 299 { 300 int i; 301 302 for (i = 0; i < sizeof(value); i++) 303 rtc_write8(reg + i, (value >> (i << 3)) & 0xff); 304 } 305 306 void rtc_init(void) 307 { 308 mc146818_init(); 309 } 310 311 #endif /* CONFIG_DM_RTC */ 312