162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <asm/tsc.h> 762306a36Sopenharmony_ci#include <linux/cpufreq.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "i915_drv.h" 1062306a36Sopenharmony_ci#include "i915_reg.h" 1162306a36Sopenharmony_ci#include "intel_gt.h" 1262306a36Sopenharmony_ci#include "intel_llc.h" 1362306a36Sopenharmony_ci#include "intel_mchbar_regs.h" 1462306a36Sopenharmony_ci#include "intel_pcode.h" 1562306a36Sopenharmony_ci#include "intel_rps.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct ia_constants { 1862306a36Sopenharmony_ci unsigned int min_gpu_freq; 1962306a36Sopenharmony_ci unsigned int max_gpu_freq; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci unsigned int min_ring_freq; 2262306a36Sopenharmony_ci unsigned int max_ia_freq; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic struct intel_gt *llc_to_gt(struct intel_llc *llc) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci return container_of(llc, struct intel_gt, llc); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic unsigned int cpu_max_MHz(void) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct cpufreq_policy *policy; 3362306a36Sopenharmony_ci unsigned int max_khz; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci policy = cpufreq_cpu_get(0); 3662306a36Sopenharmony_ci if (policy) { 3762306a36Sopenharmony_ci max_khz = policy->cpuinfo.max_freq; 3862306a36Sopenharmony_ci cpufreq_cpu_put(policy); 3962306a36Sopenharmony_ci } else { 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * Default to measured freq if none found, PCU will ensure we 4262306a36Sopenharmony_ci * don't go over 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci max_khz = tsc_khz; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return max_khz / 1000; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic bool get_ia_constants(struct intel_llc *llc, 5162306a36Sopenharmony_ci struct ia_constants *consts) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct drm_i915_private *i915 = llc_to_gt(llc)->i915; 5462306a36Sopenharmony_ci struct intel_rps *rps = &llc_to_gt(llc)->rps; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (!HAS_LLC(i915) || IS_DGFX(i915)) 5762306a36Sopenharmony_ci return false; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci consts->max_ia_freq = cpu_max_MHz(); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci consts->min_ring_freq = 6262306a36Sopenharmony_ci intel_uncore_read(llc_to_gt(llc)->uncore, DCLK) & 0xf; 6362306a36Sopenharmony_ci /* convert DDR frequency from units of 266.6MHz to bandwidth */ 6462306a36Sopenharmony_ci consts->min_ring_freq = mult_frac(consts->min_ring_freq, 8, 3); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci consts->min_gpu_freq = intel_rps_get_min_raw_freq(rps); 6762306a36Sopenharmony_ci consts->max_gpu_freq = intel_rps_get_max_raw_freq(rps); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return true; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void calc_ia_freq(struct intel_llc *llc, 7362306a36Sopenharmony_ci unsigned int gpu_freq, 7462306a36Sopenharmony_ci const struct ia_constants *consts, 7562306a36Sopenharmony_ci unsigned int *out_ia_freq, 7662306a36Sopenharmony_ci unsigned int *out_ring_freq) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct drm_i915_private *i915 = llc_to_gt(llc)->i915; 7962306a36Sopenharmony_ci const int diff = consts->max_gpu_freq - gpu_freq; 8062306a36Sopenharmony_ci unsigned int ia_freq = 0, ring_freq = 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (GRAPHICS_VER(i915) >= 9) { 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * ring_freq = 2 * GT. ring_freq is in 100MHz units 8562306a36Sopenharmony_ci * No floor required for ring frequency on SKL. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci ring_freq = gpu_freq; 8862306a36Sopenharmony_ci } else if (GRAPHICS_VER(i915) >= 8) { 8962306a36Sopenharmony_ci /* max(2 * GT, DDR). NB: GT is 50MHz units */ 9062306a36Sopenharmony_ci ring_freq = max(consts->min_ring_freq, gpu_freq); 9162306a36Sopenharmony_ci } else if (IS_HASWELL(i915)) { 9262306a36Sopenharmony_ci ring_freq = mult_frac(gpu_freq, 5, 4); 9362306a36Sopenharmony_ci ring_freq = max(consts->min_ring_freq, ring_freq); 9462306a36Sopenharmony_ci /* leave ia_freq as the default, chosen by cpufreq */ 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci const int min_freq = 15; 9762306a36Sopenharmony_ci const int scale = 180; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* 10062306a36Sopenharmony_ci * On older processors, there is no separate ring 10162306a36Sopenharmony_ci * clock domain, so in order to boost the bandwidth 10262306a36Sopenharmony_ci * of the ring, we need to upclock the CPU (ia_freq). 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * For GPU frequencies less than 750MHz, 10562306a36Sopenharmony_ci * just use the lowest ring freq. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci if (gpu_freq < min_freq) 10862306a36Sopenharmony_ci ia_freq = 800; 10962306a36Sopenharmony_ci else 11062306a36Sopenharmony_ci ia_freq = consts->max_ia_freq - diff * scale / 2; 11162306a36Sopenharmony_ci ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci *out_ia_freq = ia_freq; 11562306a36Sopenharmony_ci *out_ring_freq = ring_freq; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic void gen6_update_ring_freq(struct intel_llc *llc) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct ia_constants consts; 12162306a36Sopenharmony_ci unsigned int gpu_freq; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (!get_ia_constants(llc, &consts)) 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Although this is unlikely on any platform during initialization, 12862306a36Sopenharmony_ci * let's ensure we don't get accidentally into infinite loop 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci if (consts.max_gpu_freq <= consts.min_gpu_freq) 13162306a36Sopenharmony_ci return; 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * For each potential GPU frequency, load a ring frequency we'd like 13462306a36Sopenharmony_ci * to use for memory access. We do this by specifying the IA frequency 13562306a36Sopenharmony_ci * the PCU should use as a reference to determine the ring frequency. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci for (gpu_freq = consts.max_gpu_freq; 13862306a36Sopenharmony_ci gpu_freq >= consts.min_gpu_freq; 13962306a36Sopenharmony_ci gpu_freq--) { 14062306a36Sopenharmony_ci unsigned int ia_freq, ring_freq; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci calc_ia_freq(llc, gpu_freq, &consts, &ia_freq, &ring_freq); 14362306a36Sopenharmony_ci snb_pcode_write(llc_to_gt(llc)->uncore, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 14462306a36Sopenharmony_ci ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT | 14562306a36Sopenharmony_ci ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT | 14662306a36Sopenharmony_ci gpu_freq); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_civoid intel_llc_enable(struct intel_llc *llc) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci gen6_update_ring_freq(llc); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_civoid intel_llc_disable(struct intel_llc *llc) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci /* Currently there is no HW configuration to be done to disable. */ 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 16162306a36Sopenharmony_ci#include "selftest_llc.c" 16262306a36Sopenharmony_ci#endif 163