// SPDX-License-Identifier: GPL-2.0 // // adsp_timesync.c-- Mediatek ADSP timesync // // Copyright (c) 2020 MediaTek Inc. // Author: Celine Liu #include #include #include #include #include #include #include #include #include "adsp_core.h" #include "adsp_platform.h" #include "adsp_timesync.h" struct timesync_info_s { u32 tick_h; u32 tick_l; u32 ts_h; u32 ts_l; u32 freeze; u32 version; }; struct timesync_control_s { struct timecounter tc; struct cyclecounter cc; struct hrtimer timer; u32 period_ms; struct timesync_info_s infos; }; static struct timesync_control_s timesync_ctrl; static u64 adsp_ts_tick_read(const struct cyclecounter *cc) { return arch_timer_read_counter(); } static void adsp_timesync_update(u32 fz) { u64 tick, ts; struct timesync_info_s *infos = ×ync_ctrl.infos; int ret = 0; ts = timecounter_read(×ync_ctrl.tc); tick = timesync_ctrl.tc.cycle_last; infos->tick_h = (tick >> 32) & 0xFFFFFFFF; infos->tick_l = tick & 0xFFFFFFFF; infos->ts_h = (ts >> 32) & 0xFFFFFFFF; infos->ts_l = ts & 0xFFFFFFFF; infos->freeze = fz; infos->version++; if (is_adsp_system_running()) { ret = adsp_copy_to_sharedmem(get_adsp_core_by_id(ADSP_A_ID), ADSP_SHAREDMEM_TIMESYNC, infos, sizeof(*infos)); } } static enum hrtimer_restart adsp_timesync_refresh(struct hrtimer *hrt) { adsp_timesync_update(APTIME_UNFREEZE); hrtimer_forward_now(hrt, ms_to_ktime(timesync_ctrl.period_ms)); return HRTIMER_RESTART; } int adsp_timesync_init(void) { u32 multiplier, shifter; /* init cyclecounter mult and shift as sched_clock */ clocks_calc_mult_shift(&multiplier, &shifter, arch_timer_get_cntfrq(), NSEC_PER_SEC, 3600); timesync_ctrl.cc.read = adsp_ts_tick_read; timesync_ctrl.cc.mask = CLOCKSOURCE_MASK(56); timesync_ctrl.cc.mult = multiplier; timesync_ctrl.cc.shift = shifter; /* init time counter */ timecounter_init(×ync_ctrl.tc, ×ync_ctrl.cc, sched_clock()); /* init refresh hr_timer */ hrtimer_init(×ync_ctrl.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); timesync_ctrl.timer.function = adsp_timesync_refresh; timesync_ctrl.period_ms = TIMESYNC_WRAP_TIME_MS; pr_info("%s(), done", __func__); return 0; } void adsp_timesync_suspend(u32 fz) { hrtimer_cancel(×ync_ctrl.timer); /* update after suspend timer */ adsp_timesync_update(fz); } void adsp_timesync_resume(void) { /* re-init timecounter because sched_clock will be stopped during * suspend but arch timer counter is not, so we need to update * start time after resume */ timecounter_init(×ync_ctrl.tc, ×ync_ctrl.cc, sched_clock()); /* kick start the timer immediately */ hrtimer_start(×ync_ctrl.timer, 0, HRTIMER_MODE_REL); }