tegra: fsync: Fix tick calculation for freq generation

Use DIV_ROUND_DOWN_ULL consistently for frequency calculations to match
QNX implementation. For 30Hz signals, reference ticks were calculated
as 1041667 for a value of 1041666.67, while QNX correctly uses 1041666.

When generating precise frequencies, this rounding difference affects
how extra ticks distribute across periods (covering the 0.67 gap over
3 periods). The QNX implementation works correctly because it rounds down,
while the Linux implementation was rounding up.

This change ensures proper fractional tick distribution and prevents
signal drift over time for frequencies that aren't exact multiples of
the TSC clock unit.

Bug 5223558

Change-Id: I5fbeafd1e37c92fe95f2f3605d1ae225eacb88c8
Signed-off-by: Mohit Ingale <mohiti@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3348278
Reviewed-by: Justin Kim (SW-TEGRA) <juskim@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Ian Kaszubski <ikaszubski@nvidia.com>
This commit is contained in:
Mohit Ingale
2025-04-23 21:15:41 +00:00
committed by Jon Hunter
parent c9abbd16c0
commit 41bf84e591

View File

@@ -541,12 +541,12 @@ static int cam_fsync_program_group_generator_edges(struct fsync_generator_group
{ {
struct cam_fsync_generator *generator; struct cam_fsync_generator *generator;
u32 max_freq_hz_lcm = cam_fsync_find_max_freq_hz_lcm(group); u32 max_freq_hz_lcm = cam_fsync_find_max_freq_hz_lcm(group);
u32 const ticks_per_hz = DIV_ROUND_CLOSEST(NS_PER_SEC, group->features->ns_per_tick); u32 const ticks_per_hz = DIV_ROUND_DOWN_ULL(NS_PER_SEC, group->features->ns_per_tick);
bool const can_generate_precise_freq = cam_fsync_can_generate_precise_freq(group); bool const can_generate_precise_freq = cam_fsync_can_generate_precise_freq(group);
struct cam_fsync_extra_ticks_and_period extra = {0, 1}; struct cam_fsync_extra_ticks_and_period extra = {0, 1};
list_for_each_entry(generator, &group->generators, list) { list_for_each_entry(generator, &group->generators, list) {
u32 ref_ticks_in_period = DIV_ROUND_CLOSEST(ticks_per_hz, max_freq_hz_lcm); u32 ref_ticks_in_period = DIV_ROUND_DOWN_ULL(ticks_per_hz, max_freq_hz_lcm);
u64 ticks_in_period = (u64)ref_ticks_in_period * u64 ticks_in_period = (u64)ref_ticks_in_period *
(u64)(max_freq_hz_lcm / generator->config.freq_hz); (u64)(max_freq_hz_lcm / generator->config.freq_hz);
u64 ticks_active = mult_frac(ticks_in_period, generator->config.duty_cycle, 100); u64 ticks_active = mult_frac(ticks_in_period, generator->config.duty_cycle, 100);