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