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