void sh_rtc_set(void *cookie, struct clock_ymdhms *dt) { uint8_t r; /* stop clock */ r = _reg_read_1(SH_(RCR2)); r |= SH_RCR2_RESET; r &= ~SH_RCR2_START; _reg_write_1(SH_(RCR2), r); /* set time */ if (CPU_IS_SH3) _reg_write_1(SH3_RYRCNT, TOBCD(dt->dt_year % 100)); else _reg_write_2(SH4_RYRCNT, TOBCD(dt->dt_year % 100)); #define RTCSET(x, y) _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y)) RTCSET(MON, mon); RTCSET(WK, wday); RTCSET(DAY, day); RTCSET(HR, hour); RTCSET(MIN, min); RTCSET(SEC, sec); #undef RTCSET /* start clock */ _reg_write_1(SH_(RCR2), r | SH_RCR2_START); }
void cpu_exit(struct proc *p) { if (p->p_md.md_flags & MDP_STEP) _reg_write_2(SH_(BBRB), 0); pmap_deactivate(p); sched_exit(p); }
/* * Jump to reset vector. */ void cpu_reset() { _cpu_exception_suspend(); _reg_write_4(SH_(EXPEVT), EXPEVT_RESET_MANUAL); #ifndef __lint__ goto *(void *)0xa0000000; #endif /* NOTREACHED */ }
void machine_reset(void) { _cpu_exception_suspend(); _reg_write_4(SH_(EXPEVT), EXPEVT_RESET_MANUAL); (void)*(volatile uint32_t *)0x80000001; /* CPU shutdown */ /*NOTREACHED*/ for (;;) { continue; } }
void sh_rtc_get(void *cookie, time_t base, struct clock_ymdhms *dt) { int retry = 8; /* disable carry interrupt */ _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE); do { uint8_t r = _reg_read_1(SH_(RCR1)); r &= ~SH_RCR1_CF; r |= SH_RCR1_AF; /* don't clear alarm flag */ _reg_write_1(SH_(RCR1), r); if (CPU_IS_SH3) dt->dt_year = FROMBCD(_reg_read_1(SH3_RYRCNT)); else dt->dt_year = FROMBCD(_reg_read_2(SH4_RYRCNT) & 0x00ff); /* read counter */ #define RTCGET(x, y) dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT))) RTCGET(mon, MON); RTCGET(wday, WK); RTCGET(day, DAY); RTCGET(hour, HR); RTCGET(min, MIN); RTCGET(sec, SEC); #undef RTCGET } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0); if (retry == 0) { printf("rtc_gettime: couldn't read RTC register.\n"); memset(dt, 0, sizeof(*dt)); return; } dt->dt_year = (dt->dt_year % 100) + 1900; if (dt->dt_year < 1970) dt->dt_year += 100; }
/* * Prepare context switch from oproc to nproc. * This code is used by cpu_switchto. */ void cpu_switch_prepare(struct proc *oproc, struct proc *nproc) { nproc->p_stat = SONPROC; if (oproc && (oproc->p_md.md_flags & MDP_STEP)) _reg_write_2(SH_(BBRB), 0); curpcb = nproc->p_md.md_pcb; pmap_activate(nproc); if (nproc->p_md.md_flags & MDP_STEP) { int pm_asid = nproc->p_vmspace->vm_map.pmap->pm_asid; _reg_write_2(SH_(BBRB), 0); _reg_write_4(SH_(BARB), nproc->p_md.md_regs->tf_spc); _reg_write_1(SH_(BASRB), pm_asid); _reg_write_1(SH_(BAMRB), 0); _reg_write_2(SH_(BRCR), 0x0040); _reg_write_2(SH_(BBRB), 0x0014); } curproc = nproc; }
void sh_tlb_set_asid(int asid) { _reg_write_4(SH_(PTEH), asid); }
void sh_rtc_init(void *cookie) { /* Make sure to start RTC */ _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START); }
/* * Start the clock interrupt. */ void cpu_initclocks() { if (sh_clock.pclock == 0) panic("No PCLOCK information."); /* Set global variables. */ hz = HZ; tick = 1000000 / hz; /* * Use TMU channel 0 as hard clock */ _reg_bclr_1(SH_(TSTR), TSTR_STR0); if (sh_clock.flags & SH_CLOCK_NORTC) { /* use PCLOCK/16 as TMU0 source */ _reg_write_2(SH_(TCR0), TCR_UNIE | TCR_TPSC_P16); } else { /* use RTC clock as TMU0 source */ _reg_write_2(SH_(TCR0), TCR_UNIE | (CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC)); } sh_clock.hz_cnt = sh_clock.tmuclk / hz - 1; _reg_write_4(SH_(TCOR0), sh_clock.hz_cnt); _reg_write_4(SH_(TCNT0), sh_clock.hz_cnt); intc_intr_establish(SH_INTEVT_TMU0_TUNI0, IST_LEVEL, IPL_CLOCK, CPU_IS_SH3 ? sh3_clock_intr : sh4_clock_intr, NULL, "clock"); /* start hardclock */ _reg_bset_1(SH_(TSTR), TSTR_STR0); /* * TMU channel 1 is one shot timer for soft interrupts. */ _reg_write_2(SH_(TCR1), TCR_UNIE | TCR_TPSC_P4); _reg_write_4(SH_(TCOR1), 0xffffffff); /* * TMU channel 2 is freerunning counter for timecounter. */ _reg_write_2(SH_(TCR2), TCR_TPSC_P4); _reg_write_4(SH_(TCOR2), 0xffffffff); /* * Start and initialize timecounter. */ _reg_bset_1(SH_(TSTR), TSTR_STR2); sh_clock.tc.tc_get_timecount = sh_timecounter_get; sh_clock.tc.tc_frequency = sh_clock.pclock / 4; sh_clock.tc.tc_name = "tmu_pclock_4"; sh_clock.tc.tc_quality = 100; sh_clock.tc.tc_counter_mask = 0xffffffff; tc_init(&sh_clock.tc); /* Make sure to start RTC */ if (sh_clock.rtc.init != NULL) sh_clock.rtc.init(sh_clock.rtc._cookie); }
u_int sh_timecounter_get(struct timecounter *tc) { return 0xffffffff - _reg_read_4(SH_(TCNT2)); }
void sh_clock_init(int flags, struct rtc_ops *rtc) { uint32_t s, t0, cnt_1s; sh_clock.flags = flags; if (rtc != NULL) sh_clock.rtc = *rtc; /* structure copy */ /* Initialize TMU */ _reg_write_2(SH_(TCR0), 0); _reg_write_2(SH_(TCR1), 0); _reg_write_2(SH_(TCR2), 0); /* Reset RTC alarm and interrupt */ _reg_write_1(SH_(RCR1), 0); /* Stop all counter */ _reg_write_1(SH_(TSTR), 0); /* * Estimate CPU clock. */ if (sh_clock.flags & SH_CLOCK_NORTC) { /* Set TMU channel 0 source to PCLOCK / 16 */ _reg_write_2(SH_(TCR0), TCR_TPSC_P16); sh_clock.tmuclk = sh_clock.pclock / 16; } else { /* Set TMU channel 0 source to RTC counter clock (16.384kHz) */ _reg_write_2(SH_(TCR0), CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC); sh_clock.tmuclk = SH_RTC_CLOCK; /* Make sure RTC oscillator is enabled */ _reg_bset_1(SH_(RCR2), SH_RCR2_ENABLE); } s = _cpu_exception_suspend(); _cpu_spin(1); /* load function on cache. */ TMU_START(0); _cpu_spin(10000000); t0 = TMU_ELAPSED(0); _cpu_exception_resume(s); sh_clock.cpucycle_1us = (sh_clock.tmuclk * 10) / t0; cnt_1s = ((uint64_t)sh_clock.tmuclk * 10000000 * 10 + t0 / 2) / t0; if (CPU_IS_SH4) sh_clock.cpuclock = cnt_1s / 2; /* two-issue */ else sh_clock.cpuclock = cnt_1s; /* * Estimate PCLOCK */ if (sh_clock.pclock == 0) { uint32_t t1; /* set TMU channel 1 source to PCLOCK / 4 */ _reg_write_2(SH_(TCR1), TCR_TPSC_P4); s = _cpu_exception_suspend(); _cpu_spin(1); /* load function on cache. */ TMU_START(0); TMU_START(1); _cpu_spin(cnt_1s); /* 1 sec. */ t0 = TMU_ELAPSED(0); t1 = TMU_ELAPSED(1); _cpu_exception_resume(s); sh_clock.pclock = ((uint64_t)t1 * 4 * SH_RTC_CLOCK + t0 / 2) / t0; } /* Stop all counters */ _reg_write_1(SH_(TSTR), 0); #undef TMU_START #undef TMU_ELAPSED }
void sh_cpu_init(int arch, int product) { /* CPU type */ cpu_arch = arch; cpu_product = product; #if defined(SH3) && defined(SH4) /* Set register addresses */ sh_devreg_init(); #endif /* Cache access ops. */ sh_cache_init(); /* MMU access ops. */ sh_mmu_init(); /* Hardclock, RTC initialize. */ machine_clock_init(); /* ICU initiailze. */ curcpu()->ci_idepth = -1; intc_init(); /* Exception vector. */ memcpy(VBR + 0x100, sh_vector_generic, sh_vector_generic_end - sh_vector_generic); #ifdef SH3 if (CPU_IS_SH3) memcpy(VBR + 0x400, sh3_vector_tlbmiss, sh3_vector_tlbmiss_end - sh3_vector_tlbmiss); #endif #ifdef SH4 if (CPU_IS_SH4) memcpy(VBR + 0x400, sh4_vector_tlbmiss, sh4_vector_tlbmiss_end - sh4_vector_tlbmiss); #endif memcpy(VBR + 0x600, sh_vector_interrupt, sh_vector_interrupt_end - sh_vector_interrupt); if (!SH_HAS_UNIFIED_CACHE) sh_icache_sync_all(); __asm volatile("ldc %0, vbr" :: "r"(VBR)); /* kernel stack setup */ __sh_switch_resume = CPU_IS_SH3 ? sh3_switch_resume : sh4_switch_resume; /* Set page size (4KB) */ uvm_setpagesize(); /* setup UBC channel A for single-stepping */ #if defined(PTRACE) || defined(DDB) _reg_write_2(SH_(BBRA), 0); /* disable channel A */ _reg_write_2(SH_(BBRB), 0); /* disable channel B */ #ifdef SH3 if (CPU_IS_SH3) { /* A: break after execution, ignore ASID */ _reg_write_4(SH3_BRCR, (UBC_CTL_A_AFTER_INSN | SH3_UBC_CTL_A_MASK_ASID)); /* A: compare all address bits */ _reg_write_4(SH3_BAMRA, 0x00000000); } #endif /* SH3 */ #ifdef SH4 if (CPU_IS_SH4) { /* A: break after execution */ _reg_write_2(SH4_BRCR, UBC_CTL_A_AFTER_INSN); /* A: compare all address bits, ignore ASID */ _reg_write_1(SH4_BAMRA, SH4_UBC_MASK_NONE | SH4_UBC_MASK_ASID); } #endif /* SH4 */ #endif }