1// SPDX-License-Identifier: MIT
2/*
3 * Copyright �� 2022 Intel Corporation
4 */
5
6#include "xe_gt_clock.h"
7
8#include "regs/xe_gt_regs.h"
9#include "regs/xe_regs.h"
10#include "xe_device.h"
11#include "xe_gt.h"
12#include "xe_macros.h"
13#include "xe_mmio.h"
14
15static u32 read_reference_ts_freq(struct xe_gt *gt)
16{
17	u32 ts_override = xe_mmio_read32(gt, TIMESTAMP_OVERRIDE);
18	u32 base_freq, frac_freq;
19
20	base_freq = REG_FIELD_GET(TIMESTAMP_OVERRIDE_US_COUNTER_DIVIDER_MASK,
21				  ts_override) + 1;
22	base_freq *= 1000000;
23
24	frac_freq = REG_FIELD_GET(TIMESTAMP_OVERRIDE_US_COUNTER_DENOMINATOR_MASK,
25				  ts_override);
26	frac_freq = 1000000 / (frac_freq + 1);
27
28	return base_freq + frac_freq;
29}
30
31static u32 get_crystal_clock_freq(u32 rpm_config_reg)
32{
33	const u32 f19_2_mhz = 19200000;
34	const u32 f24_mhz = 24000000;
35	const u32 f25_mhz = 25000000;
36	const u32 f38_4_mhz = 38400000;
37	u32 crystal_clock = REG_FIELD_GET(RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK,
38					  rpm_config_reg);
39
40	switch (crystal_clock) {
41	case RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ:
42		return f24_mhz;
43	case RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ:
44		return f19_2_mhz;
45	case RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_38_4_MHZ:
46		return f38_4_mhz;
47	case RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_25_MHZ:
48		return f25_mhz;
49	default:
50		XE_WARN_ON("NOT_POSSIBLE");
51		return 0;
52	}
53}
54
55int xe_gt_clock_init(struct xe_gt *gt)
56{
57	u32 ctc_reg = xe_mmio_read32(gt, CTC_MODE);
58	u32 freq = 0;
59
60	/* Assuming gen11+ so assert this assumption is correct */
61	xe_gt_assert(gt, GRAPHICS_VER(gt_to_xe(gt)) >= 11);
62
63	if (ctc_reg & CTC_SOURCE_DIVIDE_LOGIC) {
64		freq = read_reference_ts_freq(gt);
65	} else {
66		u32 c0 = xe_mmio_read32(gt, RPM_CONFIG0);
67
68		freq = get_crystal_clock_freq(c0);
69
70		/*
71		 * Now figure out how the command stream's timestamp
72		 * register increments from this frequency (it might
73		 * increment only every few clock cycle).
74		 */
75		freq >>= 3 - REG_FIELD_GET(RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK, c0);
76	}
77
78	gt->info.reference_clock = freq;
79	return 0;
80}
81
82u64 xe_gt_clock_cycles_to_ns(const struct xe_gt *gt, u64 count)
83{
84	return DIV_ROUND_CLOSEST_ULL(count * NSEC_PER_SEC, gt->info.reference_clock);
85}
86