18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * arch/m68k/bvme6000/config.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk] 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * linux/amiga/config.c 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) 1993 Hamish Macdonald 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 138c2ecf20Sopenharmony_ci * License. See the file README.legal in the main directory of this archive 148c2ecf20Sopenharmony_ci * for more details. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/tty.h> 218c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 228c2ecf20Sopenharmony_ci#include <linux/console.h> 238c2ecf20Sopenharmony_ci#include <linux/linkage.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/major.h> 268c2ecf20Sopenharmony_ci#include <linux/genhd.h> 278c2ecf20Sopenharmony_ci#include <linux/rtc.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci#include <linux/bcd.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 328c2ecf20Sopenharmony_ci#include <asm/bootinfo-vme.h> 338c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 348c2ecf20Sopenharmony_ci#include <asm/setup.h> 358c2ecf20Sopenharmony_ci#include <asm/irq.h> 368c2ecf20Sopenharmony_ci#include <asm/traps.h> 378c2ecf20Sopenharmony_ci#include <asm/machdep.h> 388c2ecf20Sopenharmony_ci#include <asm/bvme6000hw.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void bvme6000_get_model(char *model); 418c2ecf20Sopenharmony_ciextern void bvme6000_sched_init(irq_handler_t handler); 428c2ecf20Sopenharmony_ciextern int bvme6000_hwclk (int, struct rtc_time *); 438c2ecf20Sopenharmony_ciextern void bvme6000_reset (void); 448c2ecf20Sopenharmony_civoid bvme6000_set_vectors (void); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciint __init bvme6000_parse_bootinfo(const struct bi_record *bi) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (be16_to_cpu(bi->tag) == BI_VME_TYPE) 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci return 1; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_civoid bvme6000_reset(void) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci pr_info("\r\n\nCalled bvme6000_reset\r\n" 608c2ecf20Sopenharmony_ci "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"); 618c2ecf20Sopenharmony_ci /* The string of returns is to delay the reset until the whole 628c2ecf20Sopenharmony_ci * message is output. */ 638c2ecf20Sopenharmony_ci /* Enable the watchdog, via PIT port C bit 4 */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pit->pcddr |= 0x10; /* WDOG enable */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci while(1) 688c2ecf20Sopenharmony_ci ; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void bvme6000_get_model(char *model) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci sprintf(model, "BVME%d000", m68k_cputype == CPU_68060 ? 6 : 4); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * This function is called during kernel startup to initialize 788c2ecf20Sopenharmony_ci * the bvme6000 IRQ handling routines. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic void __init bvme6000_init_IRQ(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci m68k_setup_user_interrupt(VEC_USER, 192); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid __init config_bvme6000(void) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* Board type is only set by newer versions of vmelilo/tftplilo */ 908c2ecf20Sopenharmony_ci if (!vme_brdtype) { 918c2ecf20Sopenharmony_ci if (m68k_cputype == CPU_68060) 928c2ecf20Sopenharmony_ci vme_brdtype = VME_TYPE_BVME6000; 938c2ecf20Sopenharmony_ci else 948c2ecf20Sopenharmony_ci vme_brdtype = VME_TYPE_BVME4000; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci#if 0 978c2ecf20Sopenharmony_ci /* Call bvme6000_set_vectors() so ABORT will work, along with BVMBug 988c2ecf20Sopenharmony_ci * debugger. Note trap_init() will splat the abort vector, but 998c2ecf20Sopenharmony_ci * bvme6000_init_IRQ() will put it back again. Hopefully. */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci bvme6000_set_vectors(); 1028c2ecf20Sopenharmony_ci#endif 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci mach_max_dma_address = 0xffffffff; 1058c2ecf20Sopenharmony_ci mach_sched_init = bvme6000_sched_init; 1068c2ecf20Sopenharmony_ci mach_init_IRQ = bvme6000_init_IRQ; 1078c2ecf20Sopenharmony_ci mach_hwclk = bvme6000_hwclk; 1088c2ecf20Sopenharmony_ci mach_reset = bvme6000_reset; 1098c2ecf20Sopenharmony_ci mach_get_model = bvme6000_get_model; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci pr_info("Board is %sconfigured as a System Controller\n", 1128c2ecf20Sopenharmony_ci *config_reg_ptr & BVME_CONFIG_SW1 ? "" : "not "); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Now do the PIT configuration */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci pit->pgcr = 0x00; /* Unidirectional 8 bit, no handshake for now */ 1178c2ecf20Sopenharmony_ci pit->psrr = 0x18; /* PIACK and PIRQ functions enabled */ 1188c2ecf20Sopenharmony_ci pit->pacr = 0x00; /* Sub Mode 00, H2 i/p, no DMA */ 1198c2ecf20Sopenharmony_ci pit->padr = 0x00; /* Just to be tidy! */ 1208c2ecf20Sopenharmony_ci pit->paddr = 0x00; /* All inputs for now (safest) */ 1218c2ecf20Sopenharmony_ci pit->pbcr = 0x80; /* Sub Mode 1x, H4 i/p, no DMA */ 1228c2ecf20Sopenharmony_ci pit->pbdr = 0xbc | (*config_reg_ptr & BVME_CONFIG_SW1 ? 0 : 0x40); 1238c2ecf20Sopenharmony_ci /* PRI, SYSCON?, Level3, SCC clks from xtal */ 1248c2ecf20Sopenharmony_ci pit->pbddr = 0xf3; /* Mostly outputs */ 1258c2ecf20Sopenharmony_ci pit->pcdr = 0x01; /* PA transceiver disabled */ 1268c2ecf20Sopenharmony_ci pit->pcddr = 0x03; /* WDOG disable */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* Disable snooping for Ethernet and VME accesses */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci bvme_acr_addrctl = 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciirqreturn_t bvme6000_abort_int (int irq, void *dev_id) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci unsigned long *new = (unsigned long *)vectors; 1378c2ecf20Sopenharmony_ci unsigned long *old = (unsigned long *)0xf8000000; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Wait for button release */ 1408c2ecf20Sopenharmony_ci while (*(volatile unsigned char *)BVME_LOCAL_IRQ_STAT & BVME_ABORT_STATUS) 1418c2ecf20Sopenharmony_ci ; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci *(new+4) = *(old+4); /* Illegal instruction */ 1448c2ecf20Sopenharmony_ci *(new+9) = *(old+9); /* Trace */ 1458c2ecf20Sopenharmony_ci *(new+47) = *(old+47); /* Trap #15 */ 1468c2ecf20Sopenharmony_ci *(new+0x1f) = *(old+0x1f); /* ABORT switch */ 1478c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic u64 bvme6000_read_clk(struct clocksource *cs); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic struct clocksource bvme6000_clk = { 1538c2ecf20Sopenharmony_ci .name = "rtc", 1548c2ecf20Sopenharmony_ci .rating = 250, 1558c2ecf20Sopenharmony_ci .read = bvme6000_read_clk, 1568c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(32), 1578c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic u32 clk_total, clk_offset; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define RTC_TIMER_CLOCK_FREQ 8000000 1638c2ecf20Sopenharmony_ci#define RTC_TIMER_CYCLES (RTC_TIMER_CLOCK_FREQ / HZ) 1648c2ecf20Sopenharmony_ci#define RTC_TIMER_COUNT ((RTC_TIMER_CYCLES / 2) - 1) 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic irqreturn_t bvme6000_timer_int (int irq, void *dev_id) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci irq_handler_t timer_routine = dev_id; 1698c2ecf20Sopenharmony_ci unsigned long flags; 1708c2ecf20Sopenharmony_ci volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; 1718c2ecf20Sopenharmony_ci unsigned char msr; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci local_irq_save(flags); 1748c2ecf20Sopenharmony_ci msr = rtc->msr & 0xc0; 1758c2ecf20Sopenharmony_ci rtc->msr = msr | 0x20; /* Ack the interrupt */ 1768c2ecf20Sopenharmony_ci clk_total += RTC_TIMER_CYCLES; 1778c2ecf20Sopenharmony_ci clk_offset = 0; 1788c2ecf20Sopenharmony_ci timer_routine(0, NULL); 1798c2ecf20Sopenharmony_ci local_irq_restore(flags); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * Set up the RTC timer 1 to mode 2, so T1 output toggles every 5ms 1868c2ecf20Sopenharmony_ci * (40000 x 125ns). It will interrupt every 10ms, when T1 goes low. 1878c2ecf20Sopenharmony_ci * So, when reading the elapsed time, you should read timer1, 1888c2ecf20Sopenharmony_ci * subtract it from 39999, and then add 40000 if T1 is high. 1898c2ecf20Sopenharmony_ci * That gives you the number of 125ns ticks in to the 10ms period, 1908c2ecf20Sopenharmony_ci * so divide by 8 to get the microsecond result. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_civoid bvme6000_sched_init (irq_handler_t timer_routine) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; 1968c2ecf20Sopenharmony_ci unsigned char msr = rtc->msr & 0xc0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rtc->msr = 0; /* Ensure timer registers accessible */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, IRQF_TIMER, "timer", 2018c2ecf20Sopenharmony_ci timer_routine)) 2028c2ecf20Sopenharmony_ci panic ("Couldn't register timer int"); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */ 2058c2ecf20Sopenharmony_ci rtc->t1msb = RTC_TIMER_COUNT >> 8; 2068c2ecf20Sopenharmony_ci rtc->t1lsb = RTC_TIMER_COUNT & 0xff; 2078c2ecf20Sopenharmony_ci rtc->irr_icr1 &= 0xef; /* Route timer 1 to INTR pin */ 2088c2ecf20Sopenharmony_ci rtc->msr = 0x40; /* Access int.cntrl, etc */ 2098c2ecf20Sopenharmony_ci rtc->pfr_icr0 = 0x80; /* Just timer 1 ints enabled */ 2108c2ecf20Sopenharmony_ci rtc->irr_icr1 = 0; 2118c2ecf20Sopenharmony_ci rtc->t1cr_omr = 0x0a; /* INTR+T1 active lo, push-pull */ 2128c2ecf20Sopenharmony_ci rtc->t0cr_rtmr &= 0xdf; /* Stop timers in standby */ 2138c2ecf20Sopenharmony_ci rtc->msr = 0; /* Access timer 1 control */ 2148c2ecf20Sopenharmony_ci rtc->t1cr_omr = 0x05; /* Mode 2, ext clk, GO */ 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci rtc->msr = msr; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci clocksource_register_hz(&bvme6000_clk, RTC_TIMER_CLOCK_FREQ); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0, 2218c2ecf20Sopenharmony_ci "abort", bvme6000_abort_int)) 2228c2ecf20Sopenharmony_ci panic ("Couldn't register abort int"); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * NOTE: Don't accept any readings within 5us of rollover, as 2288c2ecf20Sopenharmony_ci * the T1INT bit may be a little slow getting set. There is also 2298c2ecf20Sopenharmony_ci * a fault in the chip, meaning that reads may produce invalid 2308c2ecf20Sopenharmony_ci * results... 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic u64 bvme6000_read_clk(struct clocksource *cs) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci unsigned long flags; 2368c2ecf20Sopenharmony_ci volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; 2378c2ecf20Sopenharmony_ci volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE; 2388c2ecf20Sopenharmony_ci unsigned char msr, msb; 2398c2ecf20Sopenharmony_ci unsigned char t1int, t1op; 2408c2ecf20Sopenharmony_ci u32 v = 800000, ov; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci local_irq_save(flags); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci msr = rtc->msr & 0xc0; 2458c2ecf20Sopenharmony_ci rtc->msr = 0; /* Ensure timer registers accessible */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci do { 2488c2ecf20Sopenharmony_ci ov = v; 2498c2ecf20Sopenharmony_ci t1int = rtc->msr & 0x20; 2508c2ecf20Sopenharmony_ci t1op = pit->pcdr & 0x04; 2518c2ecf20Sopenharmony_ci rtc->t1cr_omr |= 0x40; /* Latch timer1 */ 2528c2ecf20Sopenharmony_ci msb = rtc->t1msb; /* Read timer1 */ 2538c2ecf20Sopenharmony_ci v = (msb << 8) | rtc->t1lsb; /* Read timer1 */ 2548c2ecf20Sopenharmony_ci } while (t1int != (rtc->msr & 0x20) || 2558c2ecf20Sopenharmony_ci t1op != (pit->pcdr & 0x04) || 2568c2ecf20Sopenharmony_ci abs(ov-v) > 80 || 2578c2ecf20Sopenharmony_ci v > RTC_TIMER_COUNT - (RTC_TIMER_COUNT / 100)); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci v = RTC_TIMER_COUNT - v; 2608c2ecf20Sopenharmony_ci if (!t1op) /* If in second half cycle.. */ 2618c2ecf20Sopenharmony_ci v += RTC_TIMER_CYCLES / 2; 2628c2ecf20Sopenharmony_ci if (msb > 0 && t1int) 2638c2ecf20Sopenharmony_ci clk_offset = RTC_TIMER_CYCLES; 2648c2ecf20Sopenharmony_ci rtc->msr = msr; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci v += clk_offset + clk_total; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci local_irq_restore(flags); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return v; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* 2748c2ecf20Sopenharmony_ci * Looks like op is non-zero for setting the clock, and zero for 2758c2ecf20Sopenharmony_ci * reading the clock. 2768c2ecf20Sopenharmony_ci * 2778c2ecf20Sopenharmony_ci * struct hwclk_time { 2788c2ecf20Sopenharmony_ci * unsigned sec; 0..59 2798c2ecf20Sopenharmony_ci * unsigned min; 0..59 2808c2ecf20Sopenharmony_ci * unsigned hour; 0..23 2818c2ecf20Sopenharmony_ci * unsigned day; 1..31 2828c2ecf20Sopenharmony_ci * unsigned mon; 0..11 2838c2ecf20Sopenharmony_ci * unsigned year; 00... 2848c2ecf20Sopenharmony_ci * int wday; 0..6, 0 is Sunday, -1 means unknown/don't set 2858c2ecf20Sopenharmony_ci * }; 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciint bvme6000_hwclk(int op, struct rtc_time *t) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; 2918c2ecf20Sopenharmony_ci unsigned char msr = rtc->msr & 0xc0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rtc->msr = 0x40; /* Ensure clock and real-time-mode-register 2948c2ecf20Sopenharmony_ci * are accessible */ 2958c2ecf20Sopenharmony_ci if (op) 2968c2ecf20Sopenharmony_ci { /* Write.... */ 2978c2ecf20Sopenharmony_ci rtc->t0cr_rtmr = t->tm_year%4; 2988c2ecf20Sopenharmony_ci rtc->bcd_tenms = 0; 2998c2ecf20Sopenharmony_ci rtc->bcd_sec = bin2bcd(t->tm_sec); 3008c2ecf20Sopenharmony_ci rtc->bcd_min = bin2bcd(t->tm_min); 3018c2ecf20Sopenharmony_ci rtc->bcd_hr = bin2bcd(t->tm_hour); 3028c2ecf20Sopenharmony_ci rtc->bcd_dom = bin2bcd(t->tm_mday); 3038c2ecf20Sopenharmony_ci rtc->bcd_mth = bin2bcd(t->tm_mon + 1); 3048c2ecf20Sopenharmony_ci rtc->bcd_year = bin2bcd(t->tm_year%100); 3058c2ecf20Sopenharmony_ci if (t->tm_wday >= 0) 3068c2ecf20Sopenharmony_ci rtc->bcd_dow = bin2bcd(t->tm_wday+1); 3078c2ecf20Sopenharmony_ci rtc->t0cr_rtmr = t->tm_year%4 | 0x08; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci { /* Read.... */ 3118c2ecf20Sopenharmony_ci do { 3128c2ecf20Sopenharmony_ci t->tm_sec = bcd2bin(rtc->bcd_sec); 3138c2ecf20Sopenharmony_ci t->tm_min = bcd2bin(rtc->bcd_min); 3148c2ecf20Sopenharmony_ci t->tm_hour = bcd2bin(rtc->bcd_hr); 3158c2ecf20Sopenharmony_ci t->tm_mday = bcd2bin(rtc->bcd_dom); 3168c2ecf20Sopenharmony_ci t->tm_mon = bcd2bin(rtc->bcd_mth)-1; 3178c2ecf20Sopenharmony_ci t->tm_year = bcd2bin(rtc->bcd_year); 3188c2ecf20Sopenharmony_ci if (t->tm_year < 70) 3198c2ecf20Sopenharmony_ci t->tm_year += 100; 3208c2ecf20Sopenharmony_ci t->tm_wday = bcd2bin(rtc->bcd_dow)-1; 3218c2ecf20Sopenharmony_ci } while (t->tm_sec != bcd2bin(rtc->bcd_sec)); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci rtc->msr = msr; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 328