xref: /openbmc/linux/drivers/gpu/drm/i915/gt/intel_rps.c (revision ec84b2a4)
124f90d66SChris Wilson // SPDX-License-Identifier: MIT
23e7abf81SAndi Shyti /*
33e7abf81SAndi Shyti  * Copyright © 2019 Intel Corporation
43e7abf81SAndi Shyti  */
53e7abf81SAndi Shyti 
601fabda8SLucas De Marchi #include <linux/string_helpers.h>
701fabda8SLucas De Marchi 
883d2bdb6SJani Nikula #include <drm/i915_drm.h>
983d2bdb6SJani Nikula 
10acc855d3SJani Nikula #include "display/intel_display.h"
112b874a02SJani Nikula #include "display/intel_display_irq.h"
123e7abf81SAndi Shyti #include "i915_drv.h"
1380dfdeb7SJani Nikula #include "i915_irq.h"
14476f62b8SJani Nikula #include "i915_reg.h"
15b3786b29SChris Wilson #include "intel_breadcrumbs.h"
163e7abf81SAndi Shyti #include "intel_gt.h"
179c878557SChris Wilson #include "intel_gt_clock_utils.h"
183e7abf81SAndi Shyti #include "intel_gt_irq.h"
19c1be6162STvrtko Ursulin #include "intel_gt_pm.h"
203e7abf81SAndi Shyti #include "intel_gt_pm_irq.h"
21c1be6162STvrtko Ursulin #include "intel_gt_print.h"
220d6419e9SMatt Roper #include "intel_gt_regs.h"
23e30e6c7bSMatt Roper #include "intel_mchbar_regs.h"
244dd4375bSJani Nikula #include "intel_pcode.h"
253e7abf81SAndi Shyti #include "intel_rps.h"
261eecf31eSJani Nikula #include "vlv_sideband.h"
273e7abf81SAndi Shyti #include "../../../platform/x86/intel_ips.h"
283e7abf81SAndi Shyti 
2936d516beSChris Wilson #define BUSY_MAX_EI	20u /* ms */
3036d516beSChris Wilson 
313e7abf81SAndi Shyti /*
323e7abf81SAndi Shyti  * Lock protecting IPS related data structures
333e7abf81SAndi Shyti  */
343e7abf81SAndi Shyti static DEFINE_SPINLOCK(mchdev_lock);
353e7abf81SAndi Shyti 
rps_to_gt(struct intel_rps * rps)363e7abf81SAndi Shyti static struct intel_gt *rps_to_gt(struct intel_rps *rps)
373e7abf81SAndi Shyti {
383e7abf81SAndi Shyti 	return container_of(rps, struct intel_gt, rps);
393e7abf81SAndi Shyti }
403e7abf81SAndi Shyti 
rps_to_i915(struct intel_rps * rps)413e7abf81SAndi Shyti static struct drm_i915_private *rps_to_i915(struct intel_rps *rps)
423e7abf81SAndi Shyti {
433e7abf81SAndi Shyti 	return rps_to_gt(rps)->i915;
443e7abf81SAndi Shyti }
453e7abf81SAndi Shyti 
rps_to_uncore(struct intel_rps * rps)463e7abf81SAndi Shyti static struct intel_uncore *rps_to_uncore(struct intel_rps *rps)
473e7abf81SAndi Shyti {
483e7abf81SAndi Shyti 	return rps_to_gt(rps)->uncore;
493e7abf81SAndi Shyti }
503e7abf81SAndi Shyti 
rps_to_slpc(struct intel_rps * rps)5141e5c17eSVinay Belgaumkar static struct intel_guc_slpc *rps_to_slpc(struct intel_rps *rps)
5241e5c17eSVinay Belgaumkar {
5341e5c17eSVinay Belgaumkar 	struct intel_gt *gt = rps_to_gt(rps);
5441e5c17eSVinay Belgaumkar 
5541e5c17eSVinay Belgaumkar 	return &gt->uc.guc.slpc;
5641e5c17eSVinay Belgaumkar }
5741e5c17eSVinay Belgaumkar 
rps_uses_slpc(struct intel_rps * rps)587ba79a67SVinay Belgaumkar static bool rps_uses_slpc(struct intel_rps *rps)
597ba79a67SVinay Belgaumkar {
607ba79a67SVinay Belgaumkar 	struct intel_gt *gt = rps_to_gt(rps);
617ba79a67SVinay Belgaumkar 
627ba79a67SVinay Belgaumkar 	return intel_uc_uses_guc_slpc(&gt->uc);
637ba79a67SVinay Belgaumkar }
647ba79a67SVinay Belgaumkar 
rps_pm_sanitize_mask(struct intel_rps * rps,u32 mask)653e7abf81SAndi Shyti static u32 rps_pm_sanitize_mask(struct intel_rps *rps, u32 mask)
663e7abf81SAndi Shyti {
673e7abf81SAndi Shyti 	return mask & ~rps->pm_intrmsk_mbz;
683e7abf81SAndi Shyti }
693e7abf81SAndi Shyti 
set(struct intel_uncore * uncore,i915_reg_t reg,u32 val)709834dfefSChris Wilson static void set(struct intel_uncore *uncore, i915_reg_t reg, u32 val)
7135cc7f32SChris Wilson {
7235cc7f32SChris Wilson 	intel_uncore_write_fw(uncore, reg, val);
7335cc7f32SChris Wilson }
7435cc7f32SChris Wilson 
rps_timer(struct timer_list * t)7536d516beSChris Wilson static void rps_timer(struct timer_list *t)
7636d516beSChris Wilson {
7736d516beSChris Wilson 	struct intel_rps *rps = from_timer(rps, t, timer);
78848a4e5cSLuca Coelho 	struct intel_gt *gt = rps_to_gt(rps);
7936d516beSChris Wilson 	struct intel_engine_cs *engine;
805a15550eSChris Wilson 	ktime_t dt, last, timestamp;
8136d516beSChris Wilson 	enum intel_engine_id id;
8236d516beSChris Wilson 	s64 max_busy[3] = {};
8336d516beSChris Wilson 
845a15550eSChris Wilson 	timestamp = 0;
85848a4e5cSLuca Coelho 	for_each_engine(engine, gt, id) {
8636d516beSChris Wilson 		s64 busy;
8736d516beSChris Wilson 		int i;
8836d516beSChris Wilson 
89810b7ee3SChris Wilson 		dt = intel_engine_get_busy_time(engine, &timestamp);
9036d516beSChris Wilson 		last = engine->stats.rps;
9136d516beSChris Wilson 		engine->stats.rps = dt;
9236d516beSChris Wilson 
9336d516beSChris Wilson 		busy = ktime_to_ns(ktime_sub(dt, last));
9436d516beSChris Wilson 		for (i = 0; i < ARRAY_SIZE(max_busy); i++) {
9536d516beSChris Wilson 			if (busy > max_busy[i])
9636d516beSChris Wilson 				swap(busy, max_busy[i]);
9736d516beSChris Wilson 		}
9836d516beSChris Wilson 	}
9936d516beSChris Wilson 	last = rps->pm_timestamp;
100810b7ee3SChris Wilson 	rps->pm_timestamp = timestamp;
10136d516beSChris Wilson 
10236d516beSChris Wilson 	if (intel_rps_is_active(rps)) {
10336d516beSChris Wilson 		s64 busy;
10436d516beSChris Wilson 		int i;
10536d516beSChris Wilson 
106810b7ee3SChris Wilson 		dt = ktime_sub(timestamp, last);
10736d516beSChris Wilson 
10836d516beSChris Wilson 		/*
10936d516beSChris Wilson 		 * Our goal is to evaluate each engine independently, so we run
11036d516beSChris Wilson 		 * at the lowest clocks required to sustain the heaviest
11136d516beSChris Wilson 		 * workload. However, a task may be split into sequential
11236d516beSChris Wilson 		 * dependent operations across a set of engines, such that
11336d516beSChris Wilson 		 * the independent contributions do not account for high load,
11436d516beSChris Wilson 		 * but overall the task is GPU bound. For example, consider
11536d516beSChris Wilson 		 * video decode on vcs followed by colour post-processing
11636d516beSChris Wilson 		 * on vecs, followed by general post-processing on rcs.
11736d516beSChris Wilson 		 * Since multi-engines being active does imply a single
11836d516beSChris Wilson 		 * continuous workload across all engines, we hedge our
11936d516beSChris Wilson 		 * bets by only contributing a factor of the distributed
12036d516beSChris Wilson 		 * load into our busyness calculation.
12136d516beSChris Wilson 		 */
12236d516beSChris Wilson 		busy = max_busy[0];
12336d516beSChris Wilson 		for (i = 1; i < ARRAY_SIZE(max_busy); i++) {
12436d516beSChris Wilson 			if (!max_busy[i])
12536d516beSChris Wilson 				break;
12636d516beSChris Wilson 
12736d516beSChris Wilson 			busy += div_u64(max_busy[i], 1 << i);
12836d516beSChris Wilson 		}
129848a4e5cSLuca Coelho 		GT_TRACE(gt,
13036d516beSChris Wilson 			 "busy:%lld [%d%%], max:[%lld, %lld, %lld], interval:%d\n",
13136d516beSChris Wilson 			 busy, (int)div64_u64(100 * busy, dt),
13236d516beSChris Wilson 			 max_busy[0], max_busy[1], max_busy[2],
13336d516beSChris Wilson 			 rps->pm_interval);
13436d516beSChris Wilson 
13536d516beSChris Wilson 		if (100 * busy > rps->power.up_threshold * dt &&
13636d516beSChris Wilson 		    rps->cur_freq < rps->max_freq_softlimit) {
13736d516beSChris Wilson 			rps->pm_iir |= GEN6_PM_RP_UP_THRESHOLD;
13836d516beSChris Wilson 			rps->pm_interval = 1;
139848a4e5cSLuca Coelho 			queue_work(gt->i915->unordered_wq, &rps->work);
14036d516beSChris Wilson 		} else if (100 * busy < rps->power.down_threshold * dt &&
14136d516beSChris Wilson 			   rps->cur_freq > rps->min_freq_softlimit) {
14236d516beSChris Wilson 			rps->pm_iir |= GEN6_PM_RP_DOWN_THRESHOLD;
14336d516beSChris Wilson 			rps->pm_interval = 1;
144848a4e5cSLuca Coelho 			queue_work(gt->i915->unordered_wq, &rps->work);
14536d516beSChris Wilson 		} else {
14636d516beSChris Wilson 			rps->last_adj = 0;
14736d516beSChris Wilson 		}
14836d516beSChris Wilson 
14936d516beSChris Wilson 		mod_timer(&rps->timer,
15036d516beSChris Wilson 			  jiffies + msecs_to_jiffies(rps->pm_interval));
15136d516beSChris Wilson 		rps->pm_interval = min(rps->pm_interval * 2, BUSY_MAX_EI);
15236d516beSChris Wilson 	}
15336d516beSChris Wilson }
15436d516beSChris Wilson 
rps_start_timer(struct intel_rps * rps)15536d516beSChris Wilson static void rps_start_timer(struct intel_rps *rps)
15636d516beSChris Wilson {
15736d516beSChris Wilson 	rps->pm_timestamp = ktime_sub(ktime_get(), rps->pm_timestamp);
15836d516beSChris Wilson 	rps->pm_interval = 1;
15936d516beSChris Wilson 	mod_timer(&rps->timer, jiffies + 1);
16036d516beSChris Wilson }
16136d516beSChris Wilson 
rps_stop_timer(struct intel_rps * rps)16236d516beSChris Wilson static void rps_stop_timer(struct intel_rps *rps)
16336d516beSChris Wilson {
16436d516beSChris Wilson 	del_timer_sync(&rps->timer);
16536d516beSChris Wilson 	rps->pm_timestamp = ktime_sub(ktime_get(), rps->pm_timestamp);
16636d516beSChris Wilson 	cancel_work_sync(&rps->work);
16736d516beSChris Wilson }
16836d516beSChris Wilson 
rps_pm_mask(struct intel_rps * rps,u8 val)1693e7abf81SAndi Shyti static u32 rps_pm_mask(struct intel_rps *rps, u8 val)
1703e7abf81SAndi Shyti {
1713e7abf81SAndi Shyti 	u32 mask = 0;
1723e7abf81SAndi Shyti 
1733e7abf81SAndi Shyti 	/* We use UP_EI_EXPIRED interrupts for both up/down in manual mode */
1743e7abf81SAndi Shyti 	if (val > rps->min_freq_softlimit)
1753e7abf81SAndi Shyti 		mask |= (GEN6_PM_RP_UP_EI_EXPIRED |
1763e7abf81SAndi Shyti 			 GEN6_PM_RP_DOWN_THRESHOLD |
1773e7abf81SAndi Shyti 			 GEN6_PM_RP_DOWN_TIMEOUT);
1783e7abf81SAndi Shyti 
1793e7abf81SAndi Shyti 	if (val < rps->max_freq_softlimit)
1803e7abf81SAndi Shyti 		mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
1813e7abf81SAndi Shyti 
1821ebf7aafSChris Wilson 	mask &= rps->pm_events;
1833e7abf81SAndi Shyti 
1843e7abf81SAndi Shyti 	return rps_pm_sanitize_mask(rps, ~mask);
1853e7abf81SAndi Shyti }
1863e7abf81SAndi Shyti 
rps_reset_ei(struct intel_rps * rps)1873e7abf81SAndi Shyti static void rps_reset_ei(struct intel_rps *rps)
1883e7abf81SAndi Shyti {
1893e7abf81SAndi Shyti 	memset(&rps->ei, 0, sizeof(rps->ei));
1903e7abf81SAndi Shyti }
1913e7abf81SAndi Shyti 
rps_enable_interrupts(struct intel_rps * rps)1923e7abf81SAndi Shyti static void rps_enable_interrupts(struct intel_rps *rps)
1933e7abf81SAndi Shyti {
1943e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
1953e7abf81SAndi Shyti 
1967ba79a67SVinay Belgaumkar 	GEM_BUG_ON(rps_uses_slpc(rps));
1977ba79a67SVinay Belgaumkar 
198555a3224SChris Wilson 	GT_TRACE(gt, "interrupts:on rps->pm_events: %x, rps_pm_mask:%x\n",
199555a3224SChris Wilson 		 rps->pm_events, rps_pm_mask(rps, rps->last_freq));
200555a3224SChris Wilson 
2013e7abf81SAndi Shyti 	rps_reset_ei(rps);
2023e7abf81SAndi Shyti 
20303d2c54dSMatt Roper 	spin_lock_irq(gt->irq_lock);
2043e7abf81SAndi Shyti 	gen6_gt_pm_enable_irq(gt, rps->pm_events);
20503d2c54dSMatt Roper 	spin_unlock_irq(gt->irq_lock);
2063e7abf81SAndi Shyti 
207a080bd99SChris Wilson 	intel_uncore_write(gt->uncore,
208a080bd99SChris Wilson 			   GEN6_PMINTRMSK, rps_pm_mask(rps, rps->last_freq));
2093e7abf81SAndi Shyti }
2103e7abf81SAndi Shyti 
gen6_rps_reset_interrupts(struct intel_rps * rps)2113e7abf81SAndi Shyti static void gen6_rps_reset_interrupts(struct intel_rps *rps)
2123e7abf81SAndi Shyti {
2133e7abf81SAndi Shyti 	gen6_gt_pm_reset_iir(rps_to_gt(rps), GEN6_PM_RPS_EVENTS);
2143e7abf81SAndi Shyti }
2153e7abf81SAndi Shyti 
gen11_rps_reset_interrupts(struct intel_rps * rps)2163e7abf81SAndi Shyti static void gen11_rps_reset_interrupts(struct intel_rps *rps)
2173e7abf81SAndi Shyti {
2183e7abf81SAndi Shyti 	while (gen11_gt_reset_one_iir(rps_to_gt(rps), 0, GEN11_GTPM))
2193e7abf81SAndi Shyti 		;
2203e7abf81SAndi Shyti }
2213e7abf81SAndi Shyti 
rps_reset_interrupts(struct intel_rps * rps)2223e7abf81SAndi Shyti static void rps_reset_interrupts(struct intel_rps *rps)
2233e7abf81SAndi Shyti {
2243e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
2253e7abf81SAndi Shyti 
22603d2c54dSMatt Roper 	spin_lock_irq(gt->irq_lock);
227c816723bSLucas De Marchi 	if (GRAPHICS_VER(gt->i915) >= 11)
2283e7abf81SAndi Shyti 		gen11_rps_reset_interrupts(rps);
2293e7abf81SAndi Shyti 	else
2303e7abf81SAndi Shyti 		gen6_rps_reset_interrupts(rps);
2313e7abf81SAndi Shyti 
2323e7abf81SAndi Shyti 	rps->pm_iir = 0;
23303d2c54dSMatt Roper 	spin_unlock_irq(gt->irq_lock);
2343e7abf81SAndi Shyti }
2353e7abf81SAndi Shyti 
rps_disable_interrupts(struct intel_rps * rps)2363e7abf81SAndi Shyti static void rps_disable_interrupts(struct intel_rps *rps)
2373e7abf81SAndi Shyti {
2383e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
2393e7abf81SAndi Shyti 
240a080bd99SChris Wilson 	intel_uncore_write(gt->uncore,
241a080bd99SChris Wilson 			   GEN6_PMINTRMSK, rps_pm_sanitize_mask(rps, ~0u));
2423e7abf81SAndi Shyti 
24303d2c54dSMatt Roper 	spin_lock_irq(gt->irq_lock);
2443e7abf81SAndi Shyti 	gen6_gt_pm_disable_irq(gt, GEN6_PM_RPS_EVENTS);
24503d2c54dSMatt Roper 	spin_unlock_irq(gt->irq_lock);
2463e7abf81SAndi Shyti 
2473e7abf81SAndi Shyti 	intel_synchronize_irq(gt->i915);
2483e7abf81SAndi Shyti 
2493e7abf81SAndi Shyti 	/*
2503e7abf81SAndi Shyti 	 * Now that we will not be generating any more work, flush any
2513e7abf81SAndi Shyti 	 * outstanding tasks. As we are called on the RPS idle path,
2523e7abf81SAndi Shyti 	 * we will reset the GPU to minimum frequencies, so the current
2533e7abf81SAndi Shyti 	 * state of the worker can be discarded.
2543e7abf81SAndi Shyti 	 */
2553e7abf81SAndi Shyti 	cancel_work_sync(&rps->work);
2563e7abf81SAndi Shyti 
2573e7abf81SAndi Shyti 	rps_reset_interrupts(rps);
258555a3224SChris Wilson 	GT_TRACE(gt, "interrupts:off\n");
2593e7abf81SAndi Shyti }
2603e7abf81SAndi Shyti 
2613e7abf81SAndi Shyti static const struct cparams {
2623e7abf81SAndi Shyti 	u16 i;
2633e7abf81SAndi Shyti 	u16 t;
2643e7abf81SAndi Shyti 	u16 m;
2653e7abf81SAndi Shyti 	u16 c;
2663e7abf81SAndi Shyti } cparams[] = {
2673e7abf81SAndi Shyti 	{ 1, 1333, 301, 28664 },
2683e7abf81SAndi Shyti 	{ 1, 1066, 294, 24460 },
2693e7abf81SAndi Shyti 	{ 1, 800, 294, 25192 },
2703e7abf81SAndi Shyti 	{ 0, 1333, 276, 27605 },
2713e7abf81SAndi Shyti 	{ 0, 1066, 276, 27605 },
2723e7abf81SAndi Shyti 	{ 0, 800, 231, 23784 },
2733e7abf81SAndi Shyti };
2743e7abf81SAndi Shyti 
gen5_rps_init(struct intel_rps * rps)2753e7abf81SAndi Shyti static void gen5_rps_init(struct intel_rps *rps)
2763e7abf81SAndi Shyti {
2773e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
2783e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
2793e7abf81SAndi Shyti 	u8 fmax, fmin, fstart;
2803e7abf81SAndi Shyti 	u32 rgvmodectl;
2813e7abf81SAndi Shyti 	int c_m, i;
2823e7abf81SAndi Shyti 
2833e7abf81SAndi Shyti 	if (i915->fsb_freq <= 3200)
2843e7abf81SAndi Shyti 		c_m = 0;
2853e7abf81SAndi Shyti 	else if (i915->fsb_freq <= 4800)
2863e7abf81SAndi Shyti 		c_m = 1;
2873e7abf81SAndi Shyti 	else
2883e7abf81SAndi Shyti 		c_m = 2;
2893e7abf81SAndi Shyti 
2903e7abf81SAndi Shyti 	for (i = 0; i < ARRAY_SIZE(cparams); i++) {
2913e7abf81SAndi Shyti 		if (cparams[i].i == c_m && cparams[i].t == i915->mem_freq) {
2923e7abf81SAndi Shyti 			rps->ips.m = cparams[i].m;
2933e7abf81SAndi Shyti 			rps->ips.c = cparams[i].c;
2943e7abf81SAndi Shyti 			break;
2953e7abf81SAndi Shyti 		}
2963e7abf81SAndi Shyti 	}
2973e7abf81SAndi Shyti 
2983e7abf81SAndi Shyti 	rgvmodectl = intel_uncore_read(uncore, MEMMODECTL);
2993e7abf81SAndi Shyti 
3003e7abf81SAndi Shyti 	/* Set up min, max, and cur for interrupt handling */
3013e7abf81SAndi Shyti 	fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
3023e7abf81SAndi Shyti 	fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
3033e7abf81SAndi Shyti 	fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
3043e7abf81SAndi Shyti 		MEMMODE_FSTART_SHIFT;
305a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "fmax: %d, fmin: %d, fstart: %d\n",
3063e7abf81SAndi Shyti 		fmax, fmin, fstart);
3073e7abf81SAndi Shyti 
308dd095afcSChris Wilson 	rps->min_freq = fmax;
309043cd2d1SChris Wilson 	rps->efficient_freq = fstart;
310dd095afcSChris Wilson 	rps->max_freq = fmin;
3113e7abf81SAndi Shyti }
3123e7abf81SAndi Shyti 
3133e7abf81SAndi Shyti static unsigned long
__ips_chipset_val(struct intel_ips * ips)3143e7abf81SAndi Shyti __ips_chipset_val(struct intel_ips *ips)
3153e7abf81SAndi Shyti {
3163e7abf81SAndi Shyti 	struct intel_uncore *uncore =
3173e7abf81SAndi Shyti 		rps_to_uncore(container_of(ips, struct intel_rps, ips));
3183e7abf81SAndi Shyti 	unsigned long now = jiffies_to_msecs(jiffies), dt;
3193e7abf81SAndi Shyti 	unsigned long result;
3203e7abf81SAndi Shyti 	u64 total, delta;
3213e7abf81SAndi Shyti 
3223e7abf81SAndi Shyti 	lockdep_assert_held(&mchdev_lock);
3233e7abf81SAndi Shyti 
3243e7abf81SAndi Shyti 	/*
3253e7abf81SAndi Shyti 	 * Prevent division-by-zero if we are asking too fast.
3263e7abf81SAndi Shyti 	 * Also, we don't get interesting results if we are polling
3273e7abf81SAndi Shyti 	 * faster than once in 10ms, so just return the saved value
3283e7abf81SAndi Shyti 	 * in such cases.
3293e7abf81SAndi Shyti 	 */
3303e7abf81SAndi Shyti 	dt = now - ips->last_time1;
3313e7abf81SAndi Shyti 	if (dt <= 10)
3323e7abf81SAndi Shyti 		return ips->chipset_power;
3333e7abf81SAndi Shyti 
3343e7abf81SAndi Shyti 	/* FIXME: handle per-counter overflow */
3353e7abf81SAndi Shyti 	total = intel_uncore_read(uncore, DMIEC);
3363e7abf81SAndi Shyti 	total += intel_uncore_read(uncore, DDREC);
3373e7abf81SAndi Shyti 	total += intel_uncore_read(uncore, CSIEC);
3383e7abf81SAndi Shyti 
3393e7abf81SAndi Shyti 	delta = total - ips->last_count1;
3403e7abf81SAndi Shyti 
3413e7abf81SAndi Shyti 	result = div_u64(div_u64(ips->m * delta, dt) + ips->c, 10);
3423e7abf81SAndi Shyti 
3433e7abf81SAndi Shyti 	ips->last_count1 = total;
3443e7abf81SAndi Shyti 	ips->last_time1 = now;
3453e7abf81SAndi Shyti 
3463e7abf81SAndi Shyti 	ips->chipset_power = result;
3473e7abf81SAndi Shyti 
3483e7abf81SAndi Shyti 	return result;
3493e7abf81SAndi Shyti }
3503e7abf81SAndi Shyti 
ips_mch_val(struct intel_uncore * uncore)3513e7abf81SAndi Shyti static unsigned long ips_mch_val(struct intel_uncore *uncore)
3523e7abf81SAndi Shyti {
3533e7abf81SAndi Shyti 	unsigned int m, x, b;
3543e7abf81SAndi Shyti 	u32 tsfs;
3553e7abf81SAndi Shyti 
3563e7abf81SAndi Shyti 	tsfs = intel_uncore_read(uncore, TSFS);
3573e7abf81SAndi Shyti 	x = intel_uncore_read8(uncore, TR1);
3583e7abf81SAndi Shyti 
3593e7abf81SAndi Shyti 	b = tsfs & TSFS_INTR_MASK;
3603e7abf81SAndi Shyti 	m = (tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT;
3613e7abf81SAndi Shyti 
3623e7abf81SAndi Shyti 	return m * x / 127 - b;
3633e7abf81SAndi Shyti }
3643e7abf81SAndi Shyti 
_pxvid_to_vd(u8 pxvid)3653e7abf81SAndi Shyti static int _pxvid_to_vd(u8 pxvid)
3663e7abf81SAndi Shyti {
3673e7abf81SAndi Shyti 	if (pxvid == 0)
3683e7abf81SAndi Shyti 		return 0;
3693e7abf81SAndi Shyti 
3703e7abf81SAndi Shyti 	if (pxvid >= 8 && pxvid < 31)
3713e7abf81SAndi Shyti 		pxvid = 31;
3723e7abf81SAndi Shyti 
3733e7abf81SAndi Shyti 	return (pxvid + 2) * 125;
3743e7abf81SAndi Shyti }
3753e7abf81SAndi Shyti 
pvid_to_extvid(struct drm_i915_private * i915,u8 pxvid)3763e7abf81SAndi Shyti static u32 pvid_to_extvid(struct drm_i915_private *i915, u8 pxvid)
3773e7abf81SAndi Shyti {
3783e7abf81SAndi Shyti 	const int vd = _pxvid_to_vd(pxvid);
3793e7abf81SAndi Shyti 
3803e7abf81SAndi Shyti 	if (INTEL_INFO(i915)->is_mobile)
3813e7abf81SAndi Shyti 		return max(vd - 1125, 0);
3823e7abf81SAndi Shyti 
3833e7abf81SAndi Shyti 	return vd;
3843e7abf81SAndi Shyti }
3853e7abf81SAndi Shyti 
__gen5_ips_update(struct intel_ips * ips)3863e7abf81SAndi Shyti static void __gen5_ips_update(struct intel_ips *ips)
3873e7abf81SAndi Shyti {
3883e7abf81SAndi Shyti 	struct intel_uncore *uncore =
3893e7abf81SAndi Shyti 		rps_to_uncore(container_of(ips, struct intel_rps, ips));
3903e7abf81SAndi Shyti 	u64 now, delta, dt;
3913e7abf81SAndi Shyti 	u32 count;
3923e7abf81SAndi Shyti 
3933e7abf81SAndi Shyti 	lockdep_assert_held(&mchdev_lock);
3943e7abf81SAndi Shyti 
3953e7abf81SAndi Shyti 	now = ktime_get_raw_ns();
3963e7abf81SAndi Shyti 	dt = now - ips->last_time2;
3973e7abf81SAndi Shyti 	do_div(dt, NSEC_PER_MSEC);
3983e7abf81SAndi Shyti 
3993e7abf81SAndi Shyti 	/* Don't divide by 0 */
4003e7abf81SAndi Shyti 	if (dt <= 10)
4013e7abf81SAndi Shyti 		return;
4023e7abf81SAndi Shyti 
4033e7abf81SAndi Shyti 	count = intel_uncore_read(uncore, GFXEC);
4043e7abf81SAndi Shyti 	delta = count - ips->last_count2;
4053e7abf81SAndi Shyti 
4063e7abf81SAndi Shyti 	ips->last_count2 = count;
4073e7abf81SAndi Shyti 	ips->last_time2 = now;
4083e7abf81SAndi Shyti 
4093e7abf81SAndi Shyti 	/* More magic constants... */
4103e7abf81SAndi Shyti 	ips->gfx_power = div_u64(delta * 1181, dt * 10);
4113e7abf81SAndi Shyti }
4123e7abf81SAndi Shyti 
gen5_rps_update(struct intel_rps * rps)4133e7abf81SAndi Shyti static void gen5_rps_update(struct intel_rps *rps)
4143e7abf81SAndi Shyti {
4153e7abf81SAndi Shyti 	spin_lock_irq(&mchdev_lock);
4163e7abf81SAndi Shyti 	__gen5_ips_update(&rps->ips);
4173e7abf81SAndi Shyti 	spin_unlock_irq(&mchdev_lock);
4183e7abf81SAndi Shyti }
4193e7abf81SAndi Shyti 
gen5_invert_freq(struct intel_rps * rps,unsigned int val)420e82351e7SVille Syrjälä static unsigned int gen5_invert_freq(struct intel_rps *rps,
421e82351e7SVille Syrjälä 				     unsigned int val)
422e82351e7SVille Syrjälä {
423e82351e7SVille Syrjälä 	/* Invert the frequency bin into an ips delay */
424e82351e7SVille Syrjälä 	val = rps->max_freq - val;
425e82351e7SVille Syrjälä 	val = rps->min_freq + val;
426e82351e7SVille Syrjälä 
427e82351e7SVille Syrjälä 	return val;
428e82351e7SVille Syrjälä }
429e82351e7SVille Syrjälä 
__gen5_rps_set(struct intel_rps * rps,u8 val)4304ee73792SChris Wilson static int __gen5_rps_set(struct intel_rps *rps, u8 val)
4313e7abf81SAndi Shyti {
4323e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
4333e7abf81SAndi Shyti 	u16 rgvswctl;
4343e7abf81SAndi Shyti 
4353e7abf81SAndi Shyti 	lockdep_assert_held(&mchdev_lock);
4363e7abf81SAndi Shyti 
4373e7abf81SAndi Shyti 	rgvswctl = intel_uncore_read16(uncore, MEMSWCTL);
4383e7abf81SAndi Shyti 	if (rgvswctl & MEMCTL_CMD_STS) {
439a10234fdSTvrtko Ursulin 		drm_dbg(&rps_to_i915(rps)->drm,
440a10234fdSTvrtko Ursulin 			"gpu busy, RCS change rejected\n");
4414ee73792SChris Wilson 		return -EBUSY; /* still busy with another command */
4423e7abf81SAndi Shyti 	}
4433e7abf81SAndi Shyti 
444dd095afcSChris Wilson 	/* Invert the frequency bin into an ips delay */
445e82351e7SVille Syrjälä 	val = gen5_invert_freq(rps, val);
4463e7abf81SAndi Shyti 
4473e7abf81SAndi Shyti 	rgvswctl =
4483e7abf81SAndi Shyti 		(MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
4493e7abf81SAndi Shyti 		(val << MEMCTL_FREQ_SHIFT) |
4503e7abf81SAndi Shyti 		MEMCTL_SFCAVM;
4513e7abf81SAndi Shyti 	intel_uncore_write16(uncore, MEMSWCTL, rgvswctl);
4523e7abf81SAndi Shyti 	intel_uncore_posting_read16(uncore, MEMSWCTL);
4533e7abf81SAndi Shyti 
4543e7abf81SAndi Shyti 	rgvswctl |= MEMCTL_CMD_STS;
4553e7abf81SAndi Shyti 	intel_uncore_write16(uncore, MEMSWCTL, rgvswctl);
4563e7abf81SAndi Shyti 
4574ee73792SChris Wilson 	return 0;
4584ee73792SChris Wilson }
4594ee73792SChris Wilson 
gen5_rps_set(struct intel_rps * rps,u8 val)4604ee73792SChris Wilson static int gen5_rps_set(struct intel_rps *rps, u8 val)
4614ee73792SChris Wilson {
4624ee73792SChris Wilson 	int err;
4634ee73792SChris Wilson 
4644ee73792SChris Wilson 	spin_lock_irq(&mchdev_lock);
4654ee73792SChris Wilson 	err = __gen5_rps_set(rps, val);
4664ee73792SChris Wilson 	spin_unlock_irq(&mchdev_lock);
4674ee73792SChris Wilson 
4684ee73792SChris Wilson 	return err;
4693e7abf81SAndi Shyti }
4703e7abf81SAndi Shyti 
intel_pxfreq(u32 vidfreq)4713e7abf81SAndi Shyti static unsigned long intel_pxfreq(u32 vidfreq)
4723e7abf81SAndi Shyti {
4733e7abf81SAndi Shyti 	int div = (vidfreq & 0x3f0000) >> 16;
4743e7abf81SAndi Shyti 	int post = (vidfreq & 0x3000) >> 12;
4753e7abf81SAndi Shyti 	int pre = (vidfreq & 0x7);
4763e7abf81SAndi Shyti 
4773e7abf81SAndi Shyti 	if (!pre)
4783e7abf81SAndi Shyti 		return 0;
4793e7abf81SAndi Shyti 
4803e7abf81SAndi Shyti 	return div * 133333 / (pre << post);
4813e7abf81SAndi Shyti }
4823e7abf81SAndi Shyti 
init_emon(struct intel_uncore * uncore)4833e7abf81SAndi Shyti static unsigned int init_emon(struct intel_uncore *uncore)
4843e7abf81SAndi Shyti {
4853e7abf81SAndi Shyti 	u8 pxw[16];
4863e7abf81SAndi Shyti 	int i;
4873e7abf81SAndi Shyti 
4883e7abf81SAndi Shyti 	/* Disable to program */
4893e7abf81SAndi Shyti 	intel_uncore_write(uncore, ECR, 0);
4903e7abf81SAndi Shyti 	intel_uncore_posting_read(uncore, ECR);
4913e7abf81SAndi Shyti 
4923e7abf81SAndi Shyti 	/* Program energy weights for various events */
4933e7abf81SAndi Shyti 	intel_uncore_write(uncore, SDEW, 0x15040d00);
4943e7abf81SAndi Shyti 	intel_uncore_write(uncore, CSIEW0, 0x007f0000);
4953e7abf81SAndi Shyti 	intel_uncore_write(uncore, CSIEW1, 0x1e220004);
4963e7abf81SAndi Shyti 	intel_uncore_write(uncore, CSIEW2, 0x04000004);
4973e7abf81SAndi Shyti 
4983e7abf81SAndi Shyti 	for (i = 0; i < 5; i++)
4993e7abf81SAndi Shyti 		intel_uncore_write(uncore, PEW(i), 0);
5003e7abf81SAndi Shyti 	for (i = 0; i < 3; i++)
5013e7abf81SAndi Shyti 		intel_uncore_write(uncore, DEW(i), 0);
5023e7abf81SAndi Shyti 
5033e7abf81SAndi Shyti 	/* Program P-state weights to account for frequency power adjustment */
5043e7abf81SAndi Shyti 	for (i = 0; i < 16; i++) {
5053e7abf81SAndi Shyti 		u32 pxvidfreq = intel_uncore_read(uncore, PXVFREQ(i));
5063e7abf81SAndi Shyti 		unsigned int freq = intel_pxfreq(pxvidfreq);
5073e7abf81SAndi Shyti 		unsigned int vid =
5083e7abf81SAndi Shyti 			(pxvidfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT;
5093e7abf81SAndi Shyti 		unsigned int val;
5103e7abf81SAndi Shyti 
5113e7abf81SAndi Shyti 		val = vid * vid * freq / 1000 * 255;
5123e7abf81SAndi Shyti 		val /= 127 * 127 * 900;
5133e7abf81SAndi Shyti 
5143e7abf81SAndi Shyti 		pxw[i] = val;
5153e7abf81SAndi Shyti 	}
5163e7abf81SAndi Shyti 	/* Render standby states get 0 weight */
5173e7abf81SAndi Shyti 	pxw[14] = 0;
5183e7abf81SAndi Shyti 	pxw[15] = 0;
5193e7abf81SAndi Shyti 
5203e7abf81SAndi Shyti 	for (i = 0; i < 4; i++) {
5213e7abf81SAndi Shyti 		intel_uncore_write(uncore, PXW(i),
5223e7abf81SAndi Shyti 				   pxw[i * 4 + 0] << 24 |
5233e7abf81SAndi Shyti 				   pxw[i * 4 + 1] << 16 |
5243e7abf81SAndi Shyti 				   pxw[i * 4 + 2] <<  8 |
5253e7abf81SAndi Shyti 				   pxw[i * 4 + 3] <<  0);
5263e7abf81SAndi Shyti 	}
5273e7abf81SAndi Shyti 
5283e7abf81SAndi Shyti 	/* Adjust magic regs to magic values (more experimental results) */
5293e7abf81SAndi Shyti 	intel_uncore_write(uncore, OGW0, 0);
5303e7abf81SAndi Shyti 	intel_uncore_write(uncore, OGW1, 0);
5313e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG0, 0x00007f00);
5323e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG1, 0x0000000e);
5333e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG2, 0x000e0000);
5343e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG3, 0x68000300);
5353e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG4, 0x42000000);
5363e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG5, 0x00140031);
5373e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG6, 0);
5383e7abf81SAndi Shyti 	intel_uncore_write(uncore, EG7, 0);
5393e7abf81SAndi Shyti 
5403e7abf81SAndi Shyti 	for (i = 0; i < 8; i++)
5413e7abf81SAndi Shyti 		intel_uncore_write(uncore, PXWL(i), 0);
5423e7abf81SAndi Shyti 
5433e7abf81SAndi Shyti 	/* Enable PMON + select events */
5443e7abf81SAndi Shyti 	intel_uncore_write(uncore, ECR, 0x80000019);
5453e7abf81SAndi Shyti 
5463e7abf81SAndi Shyti 	return intel_uncore_read(uncore, LCFUSE02) & LCFUSE_HIV_MASK;
5473e7abf81SAndi Shyti }
5483e7abf81SAndi Shyti 
gen5_rps_enable(struct intel_rps * rps)5493e7abf81SAndi Shyti static bool gen5_rps_enable(struct intel_rps *rps)
5503e7abf81SAndi Shyti {
551c6073d4cSVille Syrjälä 	struct drm_i915_private *i915 = rps_to_i915(rps);
5523e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
5533e7abf81SAndi Shyti 	u8 fstart, vstart;
5543e7abf81SAndi Shyti 	u32 rgvmodectl;
5553e7abf81SAndi Shyti 
5563e7abf81SAndi Shyti 	spin_lock_irq(&mchdev_lock);
5573e7abf81SAndi Shyti 
5583e7abf81SAndi Shyti 	rgvmodectl = intel_uncore_read(uncore, MEMMODECTL);
5593e7abf81SAndi Shyti 
5603e7abf81SAndi Shyti 	/* Enable temp reporting */
5613e7abf81SAndi Shyti 	intel_uncore_write16(uncore, PMMISC,
5623e7abf81SAndi Shyti 			     intel_uncore_read16(uncore, PMMISC) | MCPPCE_EN);
5633e7abf81SAndi Shyti 	intel_uncore_write16(uncore, TSC1,
5643e7abf81SAndi Shyti 			     intel_uncore_read16(uncore, TSC1) | TSE);
5653e7abf81SAndi Shyti 
5663e7abf81SAndi Shyti 	/* 100ms RC evaluation intervals */
5673e7abf81SAndi Shyti 	intel_uncore_write(uncore, RCUPEI, 100000);
5683e7abf81SAndi Shyti 	intel_uncore_write(uncore, RCDNEI, 100000);
5693e7abf81SAndi Shyti 
5703e7abf81SAndi Shyti 	/* Set max/min thresholds to 90ms and 80ms respectively */
5713e7abf81SAndi Shyti 	intel_uncore_write(uncore, RCBMAXAVG, 90000);
5723e7abf81SAndi Shyti 	intel_uncore_write(uncore, RCBMINAVG, 80000);
5733e7abf81SAndi Shyti 
5743e7abf81SAndi Shyti 	intel_uncore_write(uncore, MEMIHYST, 1);
5753e7abf81SAndi Shyti 
5763e7abf81SAndi Shyti 	/* Set up min, max, and cur for interrupt handling */
5773e7abf81SAndi Shyti 	fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
5783e7abf81SAndi Shyti 		MEMMODE_FSTART_SHIFT;
5793e7abf81SAndi Shyti 
5803e7abf81SAndi Shyti 	vstart = (intel_uncore_read(uncore, PXVFREQ(fstart)) &
5813e7abf81SAndi Shyti 		  PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT;
5823e7abf81SAndi Shyti 
5833e7abf81SAndi Shyti 	intel_uncore_write(uncore,
5843e7abf81SAndi Shyti 			   MEMINTREN,
5853e7abf81SAndi Shyti 			   MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
5863e7abf81SAndi Shyti 
5873e7abf81SAndi Shyti 	intel_uncore_write(uncore, VIDSTART, vstart);
5883e7abf81SAndi Shyti 	intel_uncore_posting_read(uncore, VIDSTART);
5893e7abf81SAndi Shyti 
5903e7abf81SAndi Shyti 	rgvmodectl |= MEMMODE_SWMODE_EN;
5913e7abf81SAndi Shyti 	intel_uncore_write(uncore, MEMMODECTL, rgvmodectl);
5923e7abf81SAndi Shyti 
5933e7abf81SAndi Shyti 	if (wait_for_atomic((intel_uncore_read(uncore, MEMSWCTL) &
5943e7abf81SAndi Shyti 			     MEMCTL_CMD_STS) == 0, 10))
595a8fa7c07SWambui Karuga 		drm_err(&uncore->i915->drm,
596a8fa7c07SWambui Karuga 			"stuck trying to change perf mode\n");
5973e7abf81SAndi Shyti 	mdelay(1);
5983e7abf81SAndi Shyti 
5994ee73792SChris Wilson 	__gen5_rps_set(rps, rps->cur_freq);
6003e7abf81SAndi Shyti 
6013e7abf81SAndi Shyti 	rps->ips.last_count1 = intel_uncore_read(uncore, DMIEC);
6023e7abf81SAndi Shyti 	rps->ips.last_count1 += intel_uncore_read(uncore, DDREC);
6033e7abf81SAndi Shyti 	rps->ips.last_count1 += intel_uncore_read(uncore, CSIEC);
6043e7abf81SAndi Shyti 	rps->ips.last_time1 = jiffies_to_msecs(jiffies);
6053e7abf81SAndi Shyti 
6063e7abf81SAndi Shyti 	rps->ips.last_count2 = intel_uncore_read(uncore, GFXEC);
6073e7abf81SAndi Shyti 	rps->ips.last_time2 = ktime_get_raw_ns();
6083e7abf81SAndi Shyti 
609c6073d4cSVille Syrjälä 	spin_lock(&i915->irq_lock);
610c6073d4cSVille Syrjälä 	ilk_enable_display_irq(i915, DE_PCU_EVENT);
611c6073d4cSVille Syrjälä 	spin_unlock(&i915->irq_lock);
612c6073d4cSVille Syrjälä 
6133e7abf81SAndi Shyti 	spin_unlock_irq(&mchdev_lock);
6143e7abf81SAndi Shyti 
6153e7abf81SAndi Shyti 	rps->ips.corr = init_emon(uncore);
6163e7abf81SAndi Shyti 
6173e7abf81SAndi Shyti 	return true;
6183e7abf81SAndi Shyti }
6193e7abf81SAndi Shyti 
gen5_rps_disable(struct intel_rps * rps)6203e7abf81SAndi Shyti static void gen5_rps_disable(struct intel_rps *rps)
6213e7abf81SAndi Shyti {
622c6073d4cSVille Syrjälä 	struct drm_i915_private *i915 = rps_to_i915(rps);
6233e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
6243e7abf81SAndi Shyti 	u16 rgvswctl;
6253e7abf81SAndi Shyti 
6263e7abf81SAndi Shyti 	spin_lock_irq(&mchdev_lock);
6273e7abf81SAndi Shyti 
628c6073d4cSVille Syrjälä 	spin_lock(&i915->irq_lock);
629c6073d4cSVille Syrjälä 	ilk_disable_display_irq(i915, DE_PCU_EVENT);
630c6073d4cSVille Syrjälä 	spin_unlock(&i915->irq_lock);
631c6073d4cSVille Syrjälä 
6323e7abf81SAndi Shyti 	rgvswctl = intel_uncore_read16(uncore, MEMSWCTL);
6333e7abf81SAndi Shyti 
6343e7abf81SAndi Shyti 	/* Ack interrupts, disable EFC interrupt */
635c61aa740SAndrzej Hajda 	intel_uncore_rmw(uncore, MEMINTREN, MEMINT_EVAL_CHG_EN, 0);
6363e7abf81SAndi Shyti 	intel_uncore_write(uncore, MEMINTRSTS, MEMINT_EVAL_CHG);
6373e7abf81SAndi Shyti 
6383e7abf81SAndi Shyti 	/* Go back to the starting frequency */
6394ee73792SChris Wilson 	__gen5_rps_set(rps, rps->idle_freq);
6403e7abf81SAndi Shyti 	mdelay(1);
6413e7abf81SAndi Shyti 	rgvswctl |= MEMCTL_CMD_STS;
6423e7abf81SAndi Shyti 	intel_uncore_write(uncore, MEMSWCTL, rgvswctl);
6433e7abf81SAndi Shyti 	mdelay(1);
6443e7abf81SAndi Shyti 
6453e7abf81SAndi Shyti 	spin_unlock_irq(&mchdev_lock);
6463e7abf81SAndi Shyti }
6473e7abf81SAndi Shyti 
rps_limits(struct intel_rps * rps,u8 val)6483e7abf81SAndi Shyti static u32 rps_limits(struct intel_rps *rps, u8 val)
6493e7abf81SAndi Shyti {
6503e7abf81SAndi Shyti 	u32 limits;
6513e7abf81SAndi Shyti 
6523e7abf81SAndi Shyti 	/*
6533e7abf81SAndi Shyti 	 * Only set the down limit when we've reached the lowest level to avoid
6543e7abf81SAndi Shyti 	 * getting more interrupts, otherwise leave this clear. This prevents a
6553e7abf81SAndi Shyti 	 * race in the hw when coming out of rc6: There's a tiny window where
6563e7abf81SAndi Shyti 	 * the hw runs at the minimal clock before selecting the desired
6573e7abf81SAndi Shyti 	 * frequency, if the down threshold expires in that window we will not
6583e7abf81SAndi Shyti 	 * receive a down interrupt.
6593e7abf81SAndi Shyti 	 */
660c816723bSLucas De Marchi 	if (GRAPHICS_VER(rps_to_i915(rps)) >= 9) {
6613e7abf81SAndi Shyti 		limits = rps->max_freq_softlimit << 23;
6623e7abf81SAndi Shyti 		if (val <= rps->min_freq_softlimit)
6633e7abf81SAndi Shyti 			limits |= rps->min_freq_softlimit << 14;
6643e7abf81SAndi Shyti 	} else {
6653e7abf81SAndi Shyti 		limits = rps->max_freq_softlimit << 24;
6663e7abf81SAndi Shyti 		if (val <= rps->min_freq_softlimit)
6673e7abf81SAndi Shyti 			limits |= rps->min_freq_softlimit << 16;
6683e7abf81SAndi Shyti 	}
6693e7abf81SAndi Shyti 
6703e7abf81SAndi Shyti 	return limits;
6713e7abf81SAndi Shyti }
6723e7abf81SAndi Shyti 
rps_set_power(struct intel_rps * rps,int new_power)6733e7abf81SAndi Shyti static void rps_set_power(struct intel_rps *rps, int new_power)
6743e7abf81SAndi Shyti {
6759c878557SChris Wilson 	struct intel_gt *gt = rps_to_gt(rps);
6769c878557SChris Wilson 	struct intel_uncore *uncore = gt->uncore;
6773e7abf81SAndi Shyti 	u32 ei_up = 0, ei_down = 0;
6783e7abf81SAndi Shyti 
6793e7abf81SAndi Shyti 	lockdep_assert_held(&rps->power.mutex);
6803e7abf81SAndi Shyti 
6813e7abf81SAndi Shyti 	if (new_power == rps->power.mode)
6823e7abf81SAndi Shyti 		return;
6833e7abf81SAndi Shyti 
6843e7abf81SAndi Shyti 	/* Note the units here are not exactly 1us, but 1280ns. */
6853e7abf81SAndi Shyti 	switch (new_power) {
6863e7abf81SAndi Shyti 	case LOW_POWER:
6873e7abf81SAndi Shyti 		ei_up = 16000;
6883e7abf81SAndi Shyti 		ei_down = 32000;
6893e7abf81SAndi Shyti 		break;
6903e7abf81SAndi Shyti 
6913e7abf81SAndi Shyti 	case BETWEEN:
6923e7abf81SAndi Shyti 		ei_up = 13000;
6933e7abf81SAndi Shyti 		ei_down = 32000;
6943e7abf81SAndi Shyti 		break;
6953e7abf81SAndi Shyti 
6963e7abf81SAndi Shyti 	case HIGH_POWER:
6973e7abf81SAndi Shyti 		ei_up = 10000;
6983e7abf81SAndi Shyti 		ei_down = 32000;
6993e7abf81SAndi Shyti 		break;
7003e7abf81SAndi Shyti 	}
7013e7abf81SAndi Shyti 
7023e7abf81SAndi Shyti 	/* When byt can survive without system hang with dynamic
7033e7abf81SAndi Shyti 	 * sw freq adjustments, this restriction can be lifted.
7043e7abf81SAndi Shyti 	 */
7059c878557SChris Wilson 	if (IS_VALLEYVIEW(gt->i915))
7063e7abf81SAndi Shyti 		goto skip_hw_write;
7073e7abf81SAndi Shyti 
7089c878557SChris Wilson 	GT_TRACE(gt,
709555a3224SChris Wilson 		 "changing power mode [%d], up %d%% @ %dus, down %d%% @ %dus\n",
710c2307b7fSTvrtko Ursulin 		 new_power,
711c2307b7fSTvrtko Ursulin 		 rps->power.up_threshold, ei_up,
712c2307b7fSTvrtko Ursulin 		 rps->power.down_threshold, ei_down);
713555a3224SChris Wilson 
7149c878557SChris Wilson 	set(uncore, GEN6_RP_UP_EI,
7159c878557SChris Wilson 	    intel_gt_ns_to_pm_interval(gt, ei_up * 1000));
71635cc7f32SChris Wilson 	set(uncore, GEN6_RP_UP_THRESHOLD,
717c2307b7fSTvrtko Ursulin 	    intel_gt_ns_to_pm_interval(gt,
718c2307b7fSTvrtko Ursulin 				       ei_up * rps->power.up_threshold * 10));
7193e7abf81SAndi Shyti 
7209c878557SChris Wilson 	set(uncore, GEN6_RP_DOWN_EI,
7219c878557SChris Wilson 	    intel_gt_ns_to_pm_interval(gt, ei_down * 1000));
72235cc7f32SChris Wilson 	set(uncore, GEN6_RP_DOWN_THRESHOLD,
723c2307b7fSTvrtko Ursulin 	    intel_gt_ns_to_pm_interval(gt,
724c2307b7fSTvrtko Ursulin 				       ei_down *
725c2307b7fSTvrtko Ursulin 				       rps->power.down_threshold * 10));
7263e7abf81SAndi Shyti 
72735cc7f32SChris Wilson 	set(uncore, GEN6_RP_CONTROL,
728c816723bSLucas De Marchi 	    (GRAPHICS_VER(gt->i915) > 9 ? 0 : GEN6_RP_MEDIA_TURBO) |
7293e7abf81SAndi Shyti 	    GEN6_RP_MEDIA_HW_NORMAL_MODE |
7303e7abf81SAndi Shyti 	    GEN6_RP_MEDIA_IS_GFX |
7313e7abf81SAndi Shyti 	    GEN6_RP_ENABLE |
7323e7abf81SAndi Shyti 	    GEN6_RP_UP_BUSY_AVG |
7333e7abf81SAndi Shyti 	    GEN6_RP_DOWN_IDLE_AVG);
7343e7abf81SAndi Shyti 
7353e7abf81SAndi Shyti skip_hw_write:
7363e7abf81SAndi Shyti 	rps->power.mode = new_power;
7373e7abf81SAndi Shyti }
7383e7abf81SAndi Shyti 
gen6_rps_set_thresholds(struct intel_rps * rps,u8 val)7393e7abf81SAndi Shyti static void gen6_rps_set_thresholds(struct intel_rps *rps, u8 val)
7403e7abf81SAndi Shyti {
7413e7abf81SAndi Shyti 	int new_power;
7423e7abf81SAndi Shyti 
7433e7abf81SAndi Shyti 	new_power = rps->power.mode;
7443e7abf81SAndi Shyti 	switch (rps->power.mode) {
7453e7abf81SAndi Shyti 	case LOW_POWER:
7463e7abf81SAndi Shyti 		if (val > rps->efficient_freq + 1 &&
7473e7abf81SAndi Shyti 		    val > rps->cur_freq)
7483e7abf81SAndi Shyti 			new_power = BETWEEN;
7493e7abf81SAndi Shyti 		break;
7503e7abf81SAndi Shyti 
7513e7abf81SAndi Shyti 	case BETWEEN:
7523e7abf81SAndi Shyti 		if (val <= rps->efficient_freq &&
7533e7abf81SAndi Shyti 		    val < rps->cur_freq)
7543e7abf81SAndi Shyti 			new_power = LOW_POWER;
7553e7abf81SAndi Shyti 		else if (val >= rps->rp0_freq &&
7563e7abf81SAndi Shyti 			 val > rps->cur_freq)
7573e7abf81SAndi Shyti 			new_power = HIGH_POWER;
7583e7abf81SAndi Shyti 		break;
7593e7abf81SAndi Shyti 
7603e7abf81SAndi Shyti 	case HIGH_POWER:
7613e7abf81SAndi Shyti 		if (val < (rps->rp1_freq + rps->rp0_freq) >> 1 &&
7623e7abf81SAndi Shyti 		    val < rps->cur_freq)
7633e7abf81SAndi Shyti 			new_power = BETWEEN;
7643e7abf81SAndi Shyti 		break;
7653e7abf81SAndi Shyti 	}
7663e7abf81SAndi Shyti 	/* Max/min bins are special */
7673e7abf81SAndi Shyti 	if (val <= rps->min_freq_softlimit)
7683e7abf81SAndi Shyti 		new_power = LOW_POWER;
7693e7abf81SAndi Shyti 	if (val >= rps->max_freq_softlimit)
7703e7abf81SAndi Shyti 		new_power = HIGH_POWER;
7713e7abf81SAndi Shyti 
7723e7abf81SAndi Shyti 	mutex_lock(&rps->power.mutex);
7733e7abf81SAndi Shyti 	if (rps->power.interactive)
7743e7abf81SAndi Shyti 		new_power = HIGH_POWER;
7753e7abf81SAndi Shyti 	rps_set_power(rps, new_power);
7763e7abf81SAndi Shyti 	mutex_unlock(&rps->power.mutex);
7773e7abf81SAndi Shyti }
7783e7abf81SAndi Shyti 
intel_rps_mark_interactive(struct intel_rps * rps,bool interactive)7793e7abf81SAndi Shyti void intel_rps_mark_interactive(struct intel_rps *rps, bool interactive)
7803e7abf81SAndi Shyti {
78101fabda8SLucas De Marchi 	GT_TRACE(rps_to_gt(rps), "mark interactive: %s\n",
78201fabda8SLucas De Marchi 		 str_yes_no(interactive));
783555a3224SChris Wilson 
7843e7abf81SAndi Shyti 	mutex_lock(&rps->power.mutex);
7853e7abf81SAndi Shyti 	if (interactive) {
7869bad2adbSChris Wilson 		if (!rps->power.interactive++ && intel_rps_is_active(rps))
7873e7abf81SAndi Shyti 			rps_set_power(rps, HIGH_POWER);
7883e7abf81SAndi Shyti 	} else {
7893e7abf81SAndi Shyti 		GEM_BUG_ON(!rps->power.interactive);
7903e7abf81SAndi Shyti 		rps->power.interactive--;
7913e7abf81SAndi Shyti 	}
7923e7abf81SAndi Shyti 	mutex_unlock(&rps->power.mutex);
7933e7abf81SAndi Shyti }
7943e7abf81SAndi Shyti 
gen6_rps_set(struct intel_rps * rps,u8 val)7953e7abf81SAndi Shyti static int gen6_rps_set(struct intel_rps *rps, u8 val)
7963e7abf81SAndi Shyti {
7973e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
7983e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
7993e7abf81SAndi Shyti 	u32 swreq;
8003e7abf81SAndi Shyti 
8017ba79a67SVinay Belgaumkar 	GEM_BUG_ON(rps_uses_slpc(rps));
8027ba79a67SVinay Belgaumkar 
803c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) >= 9)
8043e7abf81SAndi Shyti 		swreq = GEN9_FREQUENCY(val);
8053e7abf81SAndi Shyti 	else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
8063e7abf81SAndi Shyti 		swreq = HSW_FREQUENCY(val);
8073e7abf81SAndi Shyti 	else
8083e7abf81SAndi Shyti 		swreq = (GEN6_FREQUENCY(val) |
8093e7abf81SAndi Shyti 			 GEN6_OFFSET(0) |
8103e7abf81SAndi Shyti 			 GEN6_AGGRESSIVE_TURBO);
81135cc7f32SChris Wilson 	set(uncore, GEN6_RPNSWREQ, swreq);
8123e7abf81SAndi Shyti 
813555a3224SChris Wilson 	GT_TRACE(rps_to_gt(rps), "set val:%x, freq:%d, swreq:%x\n",
814555a3224SChris Wilson 		 val, intel_gpu_freq(rps, val), swreq);
815555a3224SChris Wilson 
8163e7abf81SAndi Shyti 	return 0;
8173e7abf81SAndi Shyti }
8183e7abf81SAndi Shyti 
vlv_rps_set(struct intel_rps * rps,u8 val)8193e7abf81SAndi Shyti static int vlv_rps_set(struct intel_rps *rps, u8 val)
8203e7abf81SAndi Shyti {
8213e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
8223e7abf81SAndi Shyti 	int err;
8233e7abf81SAndi Shyti 
8243e7abf81SAndi Shyti 	vlv_punit_get(i915);
8253e7abf81SAndi Shyti 	err = vlv_punit_write(i915, PUNIT_REG_GPU_FREQ_REQ, val);
8263e7abf81SAndi Shyti 	vlv_punit_put(i915);
8273e7abf81SAndi Shyti 
828555a3224SChris Wilson 	GT_TRACE(rps_to_gt(rps), "set val:%x, freq:%d\n",
829555a3224SChris Wilson 		 val, intel_gpu_freq(rps, val));
830555a3224SChris Wilson 
8313e7abf81SAndi Shyti 	return err;
8323e7abf81SAndi Shyti }
8333e7abf81SAndi Shyti 
rps_set(struct intel_rps * rps,u8 val,bool update)83428117632SChris Wilson static int rps_set(struct intel_rps *rps, u8 val, bool update)
8353e7abf81SAndi Shyti {
8363e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
8373e7abf81SAndi Shyti 	int err;
8383e7abf81SAndi Shyti 
8393e7abf81SAndi Shyti 	if (val == rps->last_freq)
8403e7abf81SAndi Shyti 		return 0;
8413e7abf81SAndi Shyti 
8423e7abf81SAndi Shyti 	if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
8433e7abf81SAndi Shyti 		err = vlv_rps_set(rps, val);
844c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
8453e7abf81SAndi Shyti 		err = gen6_rps_set(rps, val);
8464ee73792SChris Wilson 	else
8474ee73792SChris Wilson 		err = gen5_rps_set(rps, val);
8483e7abf81SAndi Shyti 	if (err)
8493e7abf81SAndi Shyti 		return err;
8503e7abf81SAndi Shyti 
851c816723bSLucas De Marchi 	if (update && GRAPHICS_VER(i915) >= 6)
8523e7abf81SAndi Shyti 		gen6_rps_set_thresholds(rps, val);
8533e7abf81SAndi Shyti 	rps->last_freq = val;
8543e7abf81SAndi Shyti 
8553e7abf81SAndi Shyti 	return 0;
8563e7abf81SAndi Shyti }
8573e7abf81SAndi Shyti 
intel_rps_unpark(struct intel_rps * rps)8583e7abf81SAndi Shyti void intel_rps_unpark(struct intel_rps *rps)
8593e7abf81SAndi Shyti {
8609bad2adbSChris Wilson 	if (!intel_rps_is_enabled(rps))
8613e7abf81SAndi Shyti 		return;
8623e7abf81SAndi Shyti 
863555a3224SChris Wilson 	GT_TRACE(rps_to_gt(rps), "unpark:%x\n", rps->cur_freq);
864555a3224SChris Wilson 
8653e7abf81SAndi Shyti 	/*
8663e7abf81SAndi Shyti 	 * Use the user's desired frequency as a guide, but for better
8673e7abf81SAndi Shyti 	 * performance, jump directly to RPe as our starting frequency.
8683e7abf81SAndi Shyti 	 */
8693e7abf81SAndi Shyti 	mutex_lock(&rps->lock);
87074e5a9acSChris Wilson 
8719bad2adbSChris Wilson 	intel_rps_set_active(rps);
872043cd2d1SChris Wilson 	intel_rps_set(rps,
873043cd2d1SChris Wilson 		      clamp(rps->cur_freq,
874043cd2d1SChris Wilson 			    rps->min_freq_softlimit,
875043cd2d1SChris Wilson 			    rps->max_freq_softlimit));
876ff345271SChris Wilson 
8773e7abf81SAndi Shyti 	mutex_unlock(&rps->lock);
8783e7abf81SAndi Shyti 
87936d516beSChris Wilson 	rps->pm_iir = 0;
8808e99299aSChris Wilson 	if (intel_rps_has_interrupts(rps))
8813e7abf81SAndi Shyti 		rps_enable_interrupts(rps);
88236d516beSChris Wilson 	if (intel_rps_uses_timer(rps))
88336d516beSChris Wilson 		rps_start_timer(rps);
8843e7abf81SAndi Shyti 
885c816723bSLucas De Marchi 	if (GRAPHICS_VER(rps_to_i915(rps)) == 5)
8863e7abf81SAndi Shyti 		gen5_rps_update(rps);
8873e7abf81SAndi Shyti }
8883e7abf81SAndi Shyti 
intel_rps_park(struct intel_rps * rps)8893e7abf81SAndi Shyti void intel_rps_park(struct intel_rps *rps)
8903e7abf81SAndi Shyti {
8913f88dde6SChris Wilson 	int adj;
8923f88dde6SChris Wilson 
8937ba79a67SVinay Belgaumkar 	if (!intel_rps_is_enabled(rps))
8947ba79a67SVinay Belgaumkar 		return;
8957ba79a67SVinay Belgaumkar 
8969bad2adbSChris Wilson 	if (!intel_rps_clear_active(rps))
8973e7abf81SAndi Shyti 		return;
8983e7abf81SAndi Shyti 
89936d516beSChris Wilson 	if (intel_rps_uses_timer(rps))
90036d516beSChris Wilson 		rps_stop_timer(rps);
9018e99299aSChris Wilson 	if (intel_rps_has_interrupts(rps))
9023e7abf81SAndi Shyti 		rps_disable_interrupts(rps);
9033e7abf81SAndi Shyti 
9043e7abf81SAndi Shyti 	if (rps->last_freq <= rps->idle_freq)
9053e7abf81SAndi Shyti 		return;
9063e7abf81SAndi Shyti 
9073e7abf81SAndi Shyti 	/*
9083e7abf81SAndi Shyti 	 * The punit delays the write of the frequency and voltage until it
9093e7abf81SAndi Shyti 	 * determines the GPU is awake. During normal usage we don't want to
9103e7abf81SAndi Shyti 	 * waste power changing the frequency if the GPU is sleeping (rc6).
9113e7abf81SAndi Shyti 	 * However, the GPU and driver is now idle and we do not want to delay
9123e7abf81SAndi Shyti 	 * switching to minimum voltage (reducing power whilst idle) as we do
9133e7abf81SAndi Shyti 	 * not expect to be woken in the near future and so must flush the
9143e7abf81SAndi Shyti 	 * change by waking the device.
9153e7abf81SAndi Shyti 	 *
9163e7abf81SAndi Shyti 	 * We choose to take the media powerwell (either would do to trick the
9173e7abf81SAndi Shyti 	 * punit into committing the voltage change) as that takes a lot less
9183e7abf81SAndi Shyti 	 * power than the render powerwell.
9193e7abf81SAndi Shyti 	 */
9203e7abf81SAndi Shyti 	intel_uncore_forcewake_get(rps_to_uncore(rps), FORCEWAKE_MEDIA);
92128117632SChris Wilson 	rps_set(rps, rps->idle_freq, false);
9223e7abf81SAndi Shyti 	intel_uncore_forcewake_put(rps_to_uncore(rps), FORCEWAKE_MEDIA);
92321abf0bfSChris Wilson 
92421abf0bfSChris Wilson 	/*
92521abf0bfSChris Wilson 	 * Since we will try and restart from the previously requested
92621abf0bfSChris Wilson 	 * frequency on unparking, treat this idle point as a downclock
92721abf0bfSChris Wilson 	 * interrupt and reduce the frequency for resume. If we park/unpark
92821abf0bfSChris Wilson 	 * more frequently than the rps worker can run, we will not respond
92921abf0bfSChris Wilson 	 * to any EI and never see a change in frequency.
93021abf0bfSChris Wilson 	 *
93121abf0bfSChris Wilson 	 * (Note we accommodate Cherryview's limitation of only using an
93221abf0bfSChris Wilson 	 * even bin by applying it to all.)
93321abf0bfSChris Wilson 	 */
9343f88dde6SChris Wilson 	adj = rps->last_adj;
9353f88dde6SChris Wilson 	if (adj < 0)
9363f88dde6SChris Wilson 		adj *= 2;
9373f88dde6SChris Wilson 	else /* CHV needs even encode values */
9383f88dde6SChris Wilson 		adj = -2;
9393f88dde6SChris Wilson 	rps->last_adj = adj;
9403f88dde6SChris Wilson 	rps->cur_freq = max_t(int, rps->cur_freq + adj, rps->min_freq);
941f7ed83ccSChris Wilson 	if (rps->cur_freq < rps->efficient_freq) {
942f7ed83ccSChris Wilson 		rps->cur_freq = rps->efficient_freq;
943f7ed83ccSChris Wilson 		rps->last_adj = 0;
944f7ed83ccSChris Wilson 	}
945555a3224SChris Wilson 
946555a3224SChris Wilson 	GT_TRACE(rps_to_gt(rps), "park:%x\n", rps->cur_freq);
9473e7abf81SAndi Shyti }
9483e7abf81SAndi Shyti 
intel_rps_get_boost_frequency(struct intel_rps * rps)9491448d5c4SVinay Belgaumkar u32 intel_rps_get_boost_frequency(struct intel_rps *rps)
9501448d5c4SVinay Belgaumkar {
9511448d5c4SVinay Belgaumkar 	struct intel_guc_slpc *slpc;
9521448d5c4SVinay Belgaumkar 
9531448d5c4SVinay Belgaumkar 	if (rps_uses_slpc(rps)) {
9541448d5c4SVinay Belgaumkar 		slpc = rps_to_slpc(rps);
9551448d5c4SVinay Belgaumkar 
9561448d5c4SVinay Belgaumkar 		return slpc->boost_freq;
9571448d5c4SVinay Belgaumkar 	} else {
9581448d5c4SVinay Belgaumkar 		return intel_gpu_freq(rps, rps->boost_freq);
9591448d5c4SVinay Belgaumkar 	}
9601448d5c4SVinay Belgaumkar }
9611448d5c4SVinay Belgaumkar 
rps_set_boost_freq(struct intel_rps * rps,u32 val)9621448d5c4SVinay Belgaumkar static int rps_set_boost_freq(struct intel_rps *rps, u32 val)
9631448d5c4SVinay Belgaumkar {
9641448d5c4SVinay Belgaumkar 	bool boost = false;
9651448d5c4SVinay Belgaumkar 
9661448d5c4SVinay Belgaumkar 	/* Validate against (static) hardware limits */
9671448d5c4SVinay Belgaumkar 	val = intel_freq_opcode(rps, val);
9681448d5c4SVinay Belgaumkar 	if (val < rps->min_freq || val > rps->max_freq)
9691448d5c4SVinay Belgaumkar 		return -EINVAL;
9701448d5c4SVinay Belgaumkar 
9711448d5c4SVinay Belgaumkar 	mutex_lock(&rps->lock);
9721448d5c4SVinay Belgaumkar 	if (val != rps->boost_freq) {
9731448d5c4SVinay Belgaumkar 		rps->boost_freq = val;
9741448d5c4SVinay Belgaumkar 		boost = atomic_read(&rps->num_waiters);
9751448d5c4SVinay Belgaumkar 	}
9761448d5c4SVinay Belgaumkar 	mutex_unlock(&rps->lock);
9771448d5c4SVinay Belgaumkar 	if (boost)
978848a4e5cSLuca Coelho 		queue_work(rps_to_gt(rps)->i915->unordered_wq, &rps->work);
9791448d5c4SVinay Belgaumkar 
9801448d5c4SVinay Belgaumkar 	return 0;
9811448d5c4SVinay Belgaumkar }
9821448d5c4SVinay Belgaumkar 
intel_rps_set_boost_frequency(struct intel_rps * rps,u32 freq)9831448d5c4SVinay Belgaumkar int intel_rps_set_boost_frequency(struct intel_rps *rps, u32 freq)
9841448d5c4SVinay Belgaumkar {
9851448d5c4SVinay Belgaumkar 	struct intel_guc_slpc *slpc;
9861448d5c4SVinay Belgaumkar 
9871448d5c4SVinay Belgaumkar 	if (rps_uses_slpc(rps)) {
9881448d5c4SVinay Belgaumkar 		slpc = rps_to_slpc(rps);
9891448d5c4SVinay Belgaumkar 
9901448d5c4SVinay Belgaumkar 		return intel_guc_slpc_set_boost_freq(slpc, freq);
9911448d5c4SVinay Belgaumkar 	} else {
9921448d5c4SVinay Belgaumkar 		return rps_set_boost_freq(rps, freq);
9931448d5c4SVinay Belgaumkar 	}
9941448d5c4SVinay Belgaumkar }
9951448d5c4SVinay Belgaumkar 
intel_rps_dec_waiters(struct intel_rps * rps)996493043feSVinay Belgaumkar void intel_rps_dec_waiters(struct intel_rps *rps)
997493043feSVinay Belgaumkar {
998493043feSVinay Belgaumkar 	struct intel_guc_slpc *slpc;
999493043feSVinay Belgaumkar 
1000493043feSVinay Belgaumkar 	if (rps_uses_slpc(rps)) {
1001493043feSVinay Belgaumkar 		slpc = rps_to_slpc(rps);
1002493043feSVinay Belgaumkar 
1003493043feSVinay Belgaumkar 		intel_guc_slpc_dec_waiters(slpc);
1004493043feSVinay Belgaumkar 	} else {
1005493043feSVinay Belgaumkar 		atomic_dec(&rps->num_waiters);
1006493043feSVinay Belgaumkar 	}
1007493043feSVinay Belgaumkar }
1008493043feSVinay Belgaumkar 
intel_rps_boost(struct i915_request * rq)10093e7abf81SAndi Shyti void intel_rps_boost(struct i915_request *rq)
10103e7abf81SAndi Shyti {
1011493043feSVinay Belgaumkar 	struct intel_guc_slpc *slpc;
1012493043feSVinay Belgaumkar 
10134e5c8a99SChris Wilson 	if (i915_request_signaled(rq) || i915_request_has_waitboost(rq))
10143e7abf81SAndi Shyti 		return;
10153e7abf81SAndi Shyti 
10163e7abf81SAndi Shyti 	/* Serializes with i915_request_retire() */
10174e5c8a99SChris Wilson 	if (!test_and_set_bit(I915_FENCE_FLAG_BOOST, &rq->fence.flags)) {
10184e5c8a99SChris Wilson 		struct intel_rps *rps = &READ_ONCE(rq->engine)->gt->rps;
10194e5c8a99SChris Wilson 
1020493043feSVinay Belgaumkar 		if (rps_uses_slpc(rps)) {
1021493043feSVinay Belgaumkar 			slpc = rps_to_slpc(rps);
1022493043feSVinay Belgaumkar 
1023f864a29aSVinay Belgaumkar 			if (slpc->min_freq_softlimit >= slpc->boost_freq)
1024f864a29aSVinay Belgaumkar 				return;
1025f864a29aSVinay Belgaumkar 
1026493043feSVinay Belgaumkar 			/* Return if old value is non zero */
1027f864a29aSVinay Belgaumkar 			if (!atomic_fetch_inc(&slpc->num_waiters)) {
1028f864a29aSVinay Belgaumkar 				GT_TRACE(rps_to_gt(rps), "boost fence:%llx:%llx\n",
1029f864a29aSVinay Belgaumkar 					 rq->fence.context, rq->fence.seqno);
1030848a4e5cSLuca Coelho 				queue_work(rps_to_gt(rps)->i915->unordered_wq,
1031848a4e5cSLuca Coelho 					   &slpc->boost_work);
1032f864a29aSVinay Belgaumkar 			}
1033493043feSVinay Belgaumkar 
1034493043feSVinay Belgaumkar 			return;
1035493043feSVinay Belgaumkar 		}
1036493043feSVinay Belgaumkar 
10374e5c8a99SChris Wilson 		if (atomic_fetch_inc(&rps->num_waiters))
10384e5c8a99SChris Wilson 			return;
10394e5c8a99SChris Wilson 
10404e5c8a99SChris Wilson 		if (!intel_rps_is_active(rps))
10414e5c8a99SChris Wilson 			return;
10423e7abf81SAndi Shyti 
1043555a3224SChris Wilson 		GT_TRACE(rps_to_gt(rps), "boost fence:%llx:%llx\n",
1044555a3224SChris Wilson 			 rq->fence.context, rq->fence.seqno);
1045555a3224SChris Wilson 
10464e5c8a99SChris Wilson 		if (READ_ONCE(rps->cur_freq) < rps->boost_freq)
1047848a4e5cSLuca Coelho 			queue_work(rps_to_gt(rps)->i915->unordered_wq, &rps->work);
10483e7abf81SAndi Shyti 
10494e5c8a99SChris Wilson 		WRITE_ONCE(rps->boosts, rps->boosts + 1); /* debug only */
10503e7abf81SAndi Shyti 	}
10513e7abf81SAndi Shyti }
10523e7abf81SAndi Shyti 
intel_rps_set(struct intel_rps * rps,u8 val)10533e7abf81SAndi Shyti int intel_rps_set(struct intel_rps *rps, u8 val)
10543e7abf81SAndi Shyti {
105535cc7f32SChris Wilson 	int err;
10563e7abf81SAndi Shyti 
10573e7abf81SAndi Shyti 	lockdep_assert_held(&rps->lock);
10583e7abf81SAndi Shyti 	GEM_BUG_ON(val > rps->max_freq);
10593e7abf81SAndi Shyti 	GEM_BUG_ON(val < rps->min_freq);
10603e7abf81SAndi Shyti 
10619bad2adbSChris Wilson 	if (intel_rps_is_active(rps)) {
106228117632SChris Wilson 		err = rps_set(rps, val, true);
106335cc7f32SChris Wilson 		if (err)
106435cc7f32SChris Wilson 			return err;
10653e7abf81SAndi Shyti 
10663e7abf81SAndi Shyti 		/*
10673e7abf81SAndi Shyti 		 * Make sure we continue to get interrupts
10683e7abf81SAndi Shyti 		 * until we hit the minimum or maximum frequencies.
10693e7abf81SAndi Shyti 		 */
10708e99299aSChris Wilson 		if (intel_rps_has_interrupts(rps)) {
10713e7abf81SAndi Shyti 			struct intel_uncore *uncore = rps_to_uncore(rps);
10723e7abf81SAndi Shyti 
107335cc7f32SChris Wilson 			set(uncore,
107435cc7f32SChris Wilson 			    GEN6_RP_INTERRUPT_LIMITS, rps_limits(rps, val));
10753e7abf81SAndi Shyti 
107635cc7f32SChris Wilson 			set(uncore, GEN6_PMINTRMSK, rps_pm_mask(rps, val));
10773e7abf81SAndi Shyti 		}
10783e7abf81SAndi Shyti 	}
10793e7abf81SAndi Shyti 
10803e7abf81SAndi Shyti 	rps->cur_freq = val;
108135cc7f32SChris Wilson 	return 0;
10823e7abf81SAndi Shyti }
10833e7abf81SAndi Shyti 
intel_rps_read_state_cap(struct intel_rps * rps)108456758cc4SAshutosh Dixit static u32 intel_rps_read_state_cap(struct intel_rps *rps)
10853e7abf81SAndi Shyti {
10863e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
108756758cc4SAshutosh Dixit 	struct intel_uncore *uncore = rps_to_uncore(rps);
10883e7abf81SAndi Shyti 
10894de23dcaSMatt Roper 	if (IS_PONTEVECCHIO(i915))
10904de23dcaSMatt Roper 		return intel_uncore_read(uncore, PVC_RP_STATE_CAP);
10914de23dcaSMatt Roper 	else if (IS_XEHPSDV(i915))
109256758cc4SAshutosh Dixit 		return intel_uncore_read(uncore, XEHPSDV_RP_STATE_CAP);
109356758cc4SAshutosh Dixit 	else if (IS_GEN9_LP(i915))
109456758cc4SAshutosh Dixit 		return intel_uncore_read(uncore, BXT_RP_STATE_CAP);
109556758cc4SAshutosh Dixit 	else
109656758cc4SAshutosh Dixit 		return intel_uncore_read(uncore, GEN6_RP_STATE_CAP);
109756758cc4SAshutosh Dixit }
109856758cc4SAshutosh Dixit 
1099835a4d18SAshutosh Dixit static void
mtl_get_freq_caps(struct intel_rps * rps,struct intel_rps_freq_caps * caps)1100835a4d18SAshutosh Dixit mtl_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
1101835a4d18SAshutosh Dixit {
1102835a4d18SAshutosh Dixit 	struct intel_uncore *uncore = rps_to_uncore(rps);
1103835a4d18SAshutosh Dixit 	u32 rp_state_cap = rps_to_gt(rps)->type == GT_MEDIA ?
1104835a4d18SAshutosh Dixit 				intel_uncore_read(uncore, MTL_MEDIAP_STATE_CAP) :
1105835a4d18SAshutosh Dixit 				intel_uncore_read(uncore, MTL_RP_STATE_CAP);
1106835a4d18SAshutosh Dixit 	u32 rpe = rps_to_gt(rps)->type == GT_MEDIA ?
1107835a4d18SAshutosh Dixit 			intel_uncore_read(uncore, MTL_MPE_FREQUENCY) :
1108835a4d18SAshutosh Dixit 			intel_uncore_read(uncore, MTL_GT_RPE_FREQUENCY);
1109835a4d18SAshutosh Dixit 
1110835a4d18SAshutosh Dixit 	/* MTL values are in units of 16.67 MHz */
1111835a4d18SAshutosh Dixit 	caps->rp0_freq = REG_FIELD_GET(MTL_RP0_CAP_MASK, rp_state_cap);
1112835a4d18SAshutosh Dixit 	caps->min_freq = REG_FIELD_GET(MTL_RPN_CAP_MASK, rp_state_cap);
1113835a4d18SAshutosh Dixit 	caps->rp1_freq = REG_FIELD_GET(MTL_RPE_MASK, rpe);
1114835a4d18SAshutosh Dixit }
1115835a4d18SAshutosh Dixit 
1116835a4d18SAshutosh Dixit static void
__gen6_rps_get_freq_caps(struct intel_rps * rps,struct intel_rps_freq_caps * caps)1117835a4d18SAshutosh Dixit __gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
111856758cc4SAshutosh Dixit {
111956758cc4SAshutosh Dixit 	struct drm_i915_private *i915 = rps_to_i915(rps);
112056758cc4SAshutosh Dixit 	u32 rp_state_cap;
112156758cc4SAshutosh Dixit 
112256758cc4SAshutosh Dixit 	rp_state_cap = intel_rps_read_state_cap(rps);
11233e7abf81SAndi Shyti 
11243e7abf81SAndi Shyti 	/* static values from HW: RP0 > RP1 > RPn (min_freq) */
11253e7abf81SAndi Shyti 	if (IS_GEN9_LP(i915)) {
112656758cc4SAshutosh Dixit 		caps->rp0_freq = (rp_state_cap >> 16) & 0xff;
112756758cc4SAshutosh Dixit 		caps->rp1_freq = (rp_state_cap >>  8) & 0xff;
112856758cc4SAshutosh Dixit 		caps->min_freq = (rp_state_cap >>  0) & 0xff;
11293e7abf81SAndi Shyti 	} else {
113056758cc4SAshutosh Dixit 		caps->rp0_freq = (rp_state_cap >>  0) & 0xff;
113195ccf312SVinay Belgaumkar 		if (GRAPHICS_VER(i915) >= 10)
113295ccf312SVinay Belgaumkar 			caps->rp1_freq = REG_FIELD_GET(RPE_MASK,
113395ccf312SVinay Belgaumkar 						       intel_uncore_read(to_gt(i915)->uncore,
113495ccf312SVinay Belgaumkar 						       GEN10_FREQ_INFO_REC));
113595ccf312SVinay Belgaumkar 		else
113656758cc4SAshutosh Dixit 			caps->rp1_freq = (rp_state_cap >>  8) & 0xff;
113756758cc4SAshutosh Dixit 		caps->min_freq = (rp_state_cap >> 16) & 0xff;
11383e7abf81SAndi Shyti 	}
11393e7abf81SAndi Shyti 
114056758cc4SAshutosh Dixit 	if (IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11) {
114156758cc4SAshutosh Dixit 		/*
114256758cc4SAshutosh Dixit 		 * In this case rp_state_cap register reports frequencies in
114356758cc4SAshutosh Dixit 		 * units of 50 MHz. Convert these to the actual "hw unit", i.e.
114456758cc4SAshutosh Dixit 		 * units of 16.67 MHz
114556758cc4SAshutosh Dixit 		 */
114656758cc4SAshutosh Dixit 		caps->rp0_freq *= GEN9_FREQ_SCALER;
114756758cc4SAshutosh Dixit 		caps->rp1_freq *= GEN9_FREQ_SCALER;
114856758cc4SAshutosh Dixit 		caps->min_freq *= GEN9_FREQ_SCALER;
114956758cc4SAshutosh Dixit 	}
115056758cc4SAshutosh Dixit }
115156758cc4SAshutosh Dixit 
1152835a4d18SAshutosh Dixit /**
1153835a4d18SAshutosh Dixit  * gen6_rps_get_freq_caps - Get freq caps exposed by HW
1154835a4d18SAshutosh Dixit  * @rps: the intel_rps structure
1155835a4d18SAshutosh Dixit  * @caps: returned freq caps
1156835a4d18SAshutosh Dixit  *
1157835a4d18SAshutosh Dixit  * Returned "caps" frequencies should be converted to MHz using
1158835a4d18SAshutosh Dixit  * intel_gpu_freq()
1159835a4d18SAshutosh Dixit  */
gen6_rps_get_freq_caps(struct intel_rps * rps,struct intel_rps_freq_caps * caps)1160835a4d18SAshutosh Dixit void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps)
1161835a4d18SAshutosh Dixit {
1162835a4d18SAshutosh Dixit 	struct drm_i915_private *i915 = rps_to_i915(rps);
1163835a4d18SAshutosh Dixit 
1164*ec84b2a4SMatt Roper 	if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
1165835a4d18SAshutosh Dixit 		return mtl_get_freq_caps(rps, caps);
1166835a4d18SAshutosh Dixit 	else
1167835a4d18SAshutosh Dixit 		return __gen6_rps_get_freq_caps(rps, caps);
1168835a4d18SAshutosh Dixit }
1169835a4d18SAshutosh Dixit 
gen6_rps_init(struct intel_rps * rps)117056758cc4SAshutosh Dixit static void gen6_rps_init(struct intel_rps *rps)
117156758cc4SAshutosh Dixit {
117256758cc4SAshutosh Dixit 	struct drm_i915_private *i915 = rps_to_i915(rps);
117356758cc4SAshutosh Dixit 	struct intel_rps_freq_caps caps;
117456758cc4SAshutosh Dixit 
117556758cc4SAshutosh Dixit 	gen6_rps_get_freq_caps(rps, &caps);
117656758cc4SAshutosh Dixit 	rps->rp0_freq = caps.rp0_freq;
117756758cc4SAshutosh Dixit 	rps->rp1_freq = caps.rp1_freq;
117856758cc4SAshutosh Dixit 	rps->min_freq = caps.min_freq;
117956758cc4SAshutosh Dixit 
11803e7abf81SAndi Shyti 	/* hw_max = RP0 until we check for overclocking */
11813e7abf81SAndi Shyti 	rps->max_freq = rps->rp0_freq;
11823e7abf81SAndi Shyti 
11833e7abf81SAndi Shyti 	rps->efficient_freq = rps->rp1_freq;
11843e7abf81SAndi Shyti 	if (IS_HASWELL(i915) || IS_BROADWELL(i915) ||
11856266992cSLucas De Marchi 	    IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11) {
11863e7abf81SAndi Shyti 		u32 ddcc_status = 0;
118756758cc4SAshutosh Dixit 		u32 mult = 1;
11883e7abf81SAndi Shyti 
118956758cc4SAshutosh Dixit 		if (IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11)
119056758cc4SAshutosh Dixit 			mult = GEN9_FREQ_SCALER;
1191ee421bb4SAshutosh Dixit 		if (snb_pcode_read(rps_to_gt(rps)->uncore,
1192ee421bb4SAshutosh Dixit 				   HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
11933e7abf81SAndi Shyti 				   &ddcc_status, NULL) == 0)
11943e7abf81SAndi Shyti 			rps->efficient_freq =
119556758cc4SAshutosh Dixit 				clamp_t(u32,
119656758cc4SAshutosh Dixit 					((ddcc_status >> 8) & 0xff) * mult,
11973e7abf81SAndi Shyti 					rps->min_freq,
11983e7abf81SAndi Shyti 					rps->max_freq);
11993e7abf81SAndi Shyti 	}
12003e7abf81SAndi Shyti }
12013e7abf81SAndi Shyti 
rps_reset(struct intel_rps * rps)12023e7abf81SAndi Shyti static bool rps_reset(struct intel_rps *rps)
12033e7abf81SAndi Shyti {
1204a8fa7c07SWambui Karuga 	struct drm_i915_private *i915 = rps_to_i915(rps);
1205555a3224SChris Wilson 
12063e7abf81SAndi Shyti 	/* force a reset */
12073e7abf81SAndi Shyti 	rps->power.mode = -1;
12083e7abf81SAndi Shyti 	rps->last_freq = -1;
12093e7abf81SAndi Shyti 
121028117632SChris Wilson 	if (rps_set(rps, rps->min_freq, true)) {
1211a8fa7c07SWambui Karuga 		drm_err(&i915->drm, "Failed to reset RPS to initial values\n");
12123e7abf81SAndi Shyti 		return false;
12133e7abf81SAndi Shyti 	}
12143e7abf81SAndi Shyti 
12153e7abf81SAndi Shyti 	rps->cur_freq = rps->min_freq;
12163e7abf81SAndi Shyti 	return true;
12173e7abf81SAndi Shyti }
12183e7abf81SAndi Shyti 
12193e7abf81SAndi Shyti /* See the Gen9_GT_PM_Programming_Guide doc for the below */
gen9_rps_enable(struct intel_rps * rps)12203e7abf81SAndi Shyti static bool gen9_rps_enable(struct intel_rps *rps)
12213e7abf81SAndi Shyti {
12229c878557SChris Wilson 	struct intel_gt *gt = rps_to_gt(rps);
12239c878557SChris Wilson 	struct intel_uncore *uncore = gt->uncore;
12243e7abf81SAndi Shyti 
12253e7abf81SAndi Shyti 	/* Program defaults and thresholds for RPS */
1226c816723bSLucas De Marchi 	if (GRAPHICS_VER(gt->i915) == 9)
12273e7abf81SAndi Shyti 		intel_uncore_write_fw(uncore, GEN6_RC_VIDEO_FREQ,
12283e7abf81SAndi Shyti 				      GEN9_FREQUENCY(rps->rp1_freq));
12293e7abf81SAndi Shyti 
12303e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_IDLE_HYSTERSIS, 0xa);
12313e7abf81SAndi Shyti 
12321ebf7aafSChris Wilson 	rps->pm_events = GEN6_PM_RP_UP_THRESHOLD | GEN6_PM_RP_DOWN_THRESHOLD;
12331ebf7aafSChris Wilson 
12343e7abf81SAndi Shyti 	return rps_reset(rps);
12353e7abf81SAndi Shyti }
12363e7abf81SAndi Shyti 
gen8_rps_enable(struct intel_rps * rps)12373e7abf81SAndi Shyti static bool gen8_rps_enable(struct intel_rps *rps)
12383e7abf81SAndi Shyti {
12393e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
12403e7abf81SAndi Shyti 
12413e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RC_VIDEO_FREQ,
12423e7abf81SAndi Shyti 			      HSW_FREQUENCY(rps->rp1_freq));
12433e7abf81SAndi Shyti 
12443e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_IDLE_HYSTERSIS, 10);
12453e7abf81SAndi Shyti 
12461ebf7aafSChris Wilson 	rps->pm_events = GEN6_PM_RP_UP_THRESHOLD | GEN6_PM_RP_DOWN_THRESHOLD;
12471ebf7aafSChris Wilson 
12483e7abf81SAndi Shyti 	return rps_reset(rps);
12493e7abf81SAndi Shyti }
12503e7abf81SAndi Shyti 
gen6_rps_enable(struct intel_rps * rps)12513e7abf81SAndi Shyti static bool gen6_rps_enable(struct intel_rps *rps)
12523e7abf81SAndi Shyti {
12533e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
12543e7abf81SAndi Shyti 
12553e7abf81SAndi Shyti 	/* Power down if completely idle for over 50ms */
12563e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_TIMEOUT, 50000);
12573e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_IDLE_HYSTERSIS, 10);
12583e7abf81SAndi Shyti 
12591ebf7aafSChris Wilson 	rps->pm_events = (GEN6_PM_RP_UP_THRESHOLD |
12601ebf7aafSChris Wilson 			  GEN6_PM_RP_DOWN_THRESHOLD |
12611ebf7aafSChris Wilson 			  GEN6_PM_RP_DOWN_TIMEOUT);
12621ebf7aafSChris Wilson 
12633e7abf81SAndi Shyti 	return rps_reset(rps);
12643e7abf81SAndi Shyti }
12653e7abf81SAndi Shyti 
chv_rps_max_freq(struct intel_rps * rps)12663e7abf81SAndi Shyti static int chv_rps_max_freq(struct intel_rps *rps)
12673e7abf81SAndi Shyti {
12683e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
12690b6613c6SVenkata Sandeep Dhanalakota 	struct intel_gt *gt = rps_to_gt(rps);
12703e7abf81SAndi Shyti 	u32 val;
12713e7abf81SAndi Shyti 
12723e7abf81SAndi Shyti 	val = vlv_punit_read(i915, FB_GFX_FMAX_AT_VMAX_FUSE);
12733e7abf81SAndi Shyti 
12740b6613c6SVenkata Sandeep Dhanalakota 	switch (gt->info.sseu.eu_total) {
12753e7abf81SAndi Shyti 	case 8:
12763e7abf81SAndi Shyti 		/* (2 * 4) config */
12773e7abf81SAndi Shyti 		val >>= FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT;
12783e7abf81SAndi Shyti 		break;
12793e7abf81SAndi Shyti 	case 12:
12803e7abf81SAndi Shyti 		/* (2 * 6) config */
12813e7abf81SAndi Shyti 		val >>= FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT;
12823e7abf81SAndi Shyti 		break;
12833e7abf81SAndi Shyti 	case 16:
12843e7abf81SAndi Shyti 		/* (2 * 8) config */
12853e7abf81SAndi Shyti 	default:
12863e7abf81SAndi Shyti 		/* Setting (2 * 8) Min RP0 for any other combination */
12873e7abf81SAndi Shyti 		val >>= FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT;
12883e7abf81SAndi Shyti 		break;
12893e7abf81SAndi Shyti 	}
12903e7abf81SAndi Shyti 
12913e7abf81SAndi Shyti 	return val & FB_GFX_FREQ_FUSE_MASK;
12923e7abf81SAndi Shyti }
12933e7abf81SAndi Shyti 
chv_rps_rpe_freq(struct intel_rps * rps)12943e7abf81SAndi Shyti static int chv_rps_rpe_freq(struct intel_rps *rps)
12953e7abf81SAndi Shyti {
12963e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
12973e7abf81SAndi Shyti 	u32 val;
12983e7abf81SAndi Shyti 
12993e7abf81SAndi Shyti 	val = vlv_punit_read(i915, PUNIT_GPU_DUTYCYCLE_REG);
13003e7abf81SAndi Shyti 	val >>= PUNIT_GPU_DUTYCYCLE_RPE_FREQ_SHIFT;
13013e7abf81SAndi Shyti 
13023e7abf81SAndi Shyti 	return val & PUNIT_GPU_DUTYCYCLE_RPE_FREQ_MASK;
13033e7abf81SAndi Shyti }
13043e7abf81SAndi Shyti 
chv_rps_guar_freq(struct intel_rps * rps)13053e7abf81SAndi Shyti static int chv_rps_guar_freq(struct intel_rps *rps)
13063e7abf81SAndi Shyti {
13073e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
13083e7abf81SAndi Shyti 	u32 val;
13093e7abf81SAndi Shyti 
13103e7abf81SAndi Shyti 	val = vlv_punit_read(i915, FB_GFX_FMAX_AT_VMAX_FUSE);
13113e7abf81SAndi Shyti 
13123e7abf81SAndi Shyti 	return val & FB_GFX_FREQ_FUSE_MASK;
13133e7abf81SAndi Shyti }
13143e7abf81SAndi Shyti 
chv_rps_min_freq(struct intel_rps * rps)13153e7abf81SAndi Shyti static u32 chv_rps_min_freq(struct intel_rps *rps)
13163e7abf81SAndi Shyti {
13173e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
13183e7abf81SAndi Shyti 	u32 val;
13193e7abf81SAndi Shyti 
13203e7abf81SAndi Shyti 	val = vlv_punit_read(i915, FB_GFX_FMIN_AT_VMIN_FUSE);
13213e7abf81SAndi Shyti 	val >>= FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT;
13223e7abf81SAndi Shyti 
13233e7abf81SAndi Shyti 	return val & FB_GFX_FREQ_FUSE_MASK;
13243e7abf81SAndi Shyti }
13253e7abf81SAndi Shyti 
chv_rps_enable(struct intel_rps * rps)13263e7abf81SAndi Shyti static bool chv_rps_enable(struct intel_rps *rps)
13273e7abf81SAndi Shyti {
13283e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
13293e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
13303e7abf81SAndi Shyti 	u32 val;
13313e7abf81SAndi Shyti 
13323e7abf81SAndi Shyti 	/* 1: Program defaults and thresholds for RPS*/
13333e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_TIMEOUT, 1000000);
13343e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_UP_THRESHOLD, 59400);
13353e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_THRESHOLD, 245000);
13363e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_UP_EI, 66000);
13373e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_EI, 350000);
13383e7abf81SAndi Shyti 
13393e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_IDLE_HYSTERSIS, 10);
13403e7abf81SAndi Shyti 
13413e7abf81SAndi Shyti 	/* 2: Enable RPS */
13423e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_CONTROL,
13433e7abf81SAndi Shyti 			      GEN6_RP_MEDIA_HW_NORMAL_MODE |
13443e7abf81SAndi Shyti 			      GEN6_RP_MEDIA_IS_GFX |
13453e7abf81SAndi Shyti 			      GEN6_RP_ENABLE |
13463e7abf81SAndi Shyti 			      GEN6_RP_UP_BUSY_AVG |
13473e7abf81SAndi Shyti 			      GEN6_RP_DOWN_IDLE_AVG);
13483e7abf81SAndi Shyti 
13491ebf7aafSChris Wilson 	rps->pm_events = (GEN6_PM_RP_UP_THRESHOLD |
13501ebf7aafSChris Wilson 			  GEN6_PM_RP_DOWN_THRESHOLD |
13511ebf7aafSChris Wilson 			  GEN6_PM_RP_DOWN_TIMEOUT);
13521ebf7aafSChris Wilson 
13533e7abf81SAndi Shyti 	/* Setting Fixed Bias */
13543e7abf81SAndi Shyti 	vlv_punit_get(i915);
13553e7abf81SAndi Shyti 
13563e7abf81SAndi Shyti 	val = VLV_OVERRIDE_EN | VLV_SOC_TDP_EN | CHV_BIAS_CPU_50_SOC_50;
13573e7abf81SAndi Shyti 	vlv_punit_write(i915, VLV_TURBO_SOC_OVERRIDE, val);
13583e7abf81SAndi Shyti 
13593e7abf81SAndi Shyti 	val = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
13603e7abf81SAndi Shyti 
13613e7abf81SAndi Shyti 	vlv_punit_put(i915);
13623e7abf81SAndi Shyti 
13633e7abf81SAndi Shyti 	/* RPS code assumes GPLL is used */
13640d4c351aSPankaj Bharadiya 	drm_WARN_ONCE(&i915->drm, (val & GPLLENABLE) == 0,
13650d4c351aSPankaj Bharadiya 		      "GPLL not enabled\n");
13663e7abf81SAndi Shyti 
136701fabda8SLucas De Marchi 	drm_dbg(&i915->drm, "GPLL enabled? %s\n",
136801fabda8SLucas De Marchi 		str_yes_no(val & GPLLENABLE));
1369a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "GPU status: 0x%08x\n", val);
13703e7abf81SAndi Shyti 
13713e7abf81SAndi Shyti 	return rps_reset(rps);
13723e7abf81SAndi Shyti }
13733e7abf81SAndi Shyti 
vlv_rps_guar_freq(struct intel_rps * rps)13743e7abf81SAndi Shyti static int vlv_rps_guar_freq(struct intel_rps *rps)
13753e7abf81SAndi Shyti {
13763e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
13773e7abf81SAndi Shyti 	u32 val, rp1;
13783e7abf81SAndi Shyti 
13793e7abf81SAndi Shyti 	val = vlv_nc_read(i915, IOSF_NC_FB_GFX_FREQ_FUSE);
13803e7abf81SAndi Shyti 
13813e7abf81SAndi Shyti 	rp1 = val & FB_GFX_FGUARANTEED_FREQ_FUSE_MASK;
13823e7abf81SAndi Shyti 	rp1 >>= FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT;
13833e7abf81SAndi Shyti 
13843e7abf81SAndi Shyti 	return rp1;
13853e7abf81SAndi Shyti }
13863e7abf81SAndi Shyti 
vlv_rps_max_freq(struct intel_rps * rps)13873e7abf81SAndi Shyti static int vlv_rps_max_freq(struct intel_rps *rps)
13883e7abf81SAndi Shyti {
13893e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
13903e7abf81SAndi Shyti 	u32 val, rp0;
13913e7abf81SAndi Shyti 
13923e7abf81SAndi Shyti 	val = vlv_nc_read(i915, IOSF_NC_FB_GFX_FREQ_FUSE);
13933e7abf81SAndi Shyti 
13943e7abf81SAndi Shyti 	rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT;
13953e7abf81SAndi Shyti 	/* Clamp to max */
13963e7abf81SAndi Shyti 	rp0 = min_t(u32, rp0, 0xea);
13973e7abf81SAndi Shyti 
13983e7abf81SAndi Shyti 	return rp0;
13993e7abf81SAndi Shyti }
14003e7abf81SAndi Shyti 
vlv_rps_rpe_freq(struct intel_rps * rps)14013e7abf81SAndi Shyti static int vlv_rps_rpe_freq(struct intel_rps *rps)
14023e7abf81SAndi Shyti {
14033e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
14043e7abf81SAndi Shyti 	u32 val, rpe;
14053e7abf81SAndi Shyti 
14063e7abf81SAndi Shyti 	val = vlv_nc_read(i915, IOSF_NC_FB_GFX_FMAX_FUSE_LO);
14073e7abf81SAndi Shyti 	rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT;
14083e7abf81SAndi Shyti 	val = vlv_nc_read(i915, IOSF_NC_FB_GFX_FMAX_FUSE_HI);
14093e7abf81SAndi Shyti 	rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5;
14103e7abf81SAndi Shyti 
14113e7abf81SAndi Shyti 	return rpe;
14123e7abf81SAndi Shyti }
14133e7abf81SAndi Shyti 
vlv_rps_min_freq(struct intel_rps * rps)14143e7abf81SAndi Shyti static int vlv_rps_min_freq(struct intel_rps *rps)
14153e7abf81SAndi Shyti {
14163e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
14173e7abf81SAndi Shyti 	u32 val;
14183e7abf81SAndi Shyti 
14193e7abf81SAndi Shyti 	val = vlv_punit_read(i915, PUNIT_REG_GPU_LFM) & 0xff;
14203e7abf81SAndi Shyti 	/*
14213e7abf81SAndi Shyti 	 * According to the BYT Punit GPU turbo HAS 1.1.6.3 the minimum value
14223e7abf81SAndi Shyti 	 * for the minimum frequency in GPLL mode is 0xc1. Contrary to this on
14233e7abf81SAndi Shyti 	 * a BYT-M B0 the above register contains 0xbf. Moreover when setting
14243e7abf81SAndi Shyti 	 * a frequency Punit will not allow values below 0xc0. Clamp it 0xc0
14253e7abf81SAndi Shyti 	 * to make sure it matches what Punit accepts.
14263e7abf81SAndi Shyti 	 */
14273e7abf81SAndi Shyti 	return max_t(u32, val, 0xc0);
14283e7abf81SAndi Shyti }
14293e7abf81SAndi Shyti 
vlv_rps_enable(struct intel_rps * rps)14303e7abf81SAndi Shyti static bool vlv_rps_enable(struct intel_rps *rps)
14313e7abf81SAndi Shyti {
14323e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
14333e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
14343e7abf81SAndi Shyti 	u32 val;
14353e7abf81SAndi Shyti 
14363e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_TIMEOUT, 1000000);
14373e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_UP_THRESHOLD, 59400);
14383e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_THRESHOLD, 245000);
14393e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_UP_EI, 66000);
14403e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_DOWN_EI, 350000);
14413e7abf81SAndi Shyti 
14423e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_IDLE_HYSTERSIS, 10);
14433e7abf81SAndi Shyti 
14443e7abf81SAndi Shyti 	intel_uncore_write_fw(uncore, GEN6_RP_CONTROL,
14453e7abf81SAndi Shyti 			      GEN6_RP_MEDIA_TURBO |
14463e7abf81SAndi Shyti 			      GEN6_RP_MEDIA_HW_NORMAL_MODE |
14473e7abf81SAndi Shyti 			      GEN6_RP_MEDIA_IS_GFX |
14483e7abf81SAndi Shyti 			      GEN6_RP_ENABLE |
14493e7abf81SAndi Shyti 			      GEN6_RP_UP_BUSY_AVG |
14503e7abf81SAndi Shyti 			      GEN6_RP_DOWN_IDLE_CONT);
14513e7abf81SAndi Shyti 
14521ebf7aafSChris Wilson 	/* WaGsvRC0ResidencyMethod:vlv */
14531ebf7aafSChris Wilson 	rps->pm_events = GEN6_PM_RP_UP_EI_EXPIRED;
14541ebf7aafSChris Wilson 
14553e7abf81SAndi Shyti 	vlv_punit_get(i915);
14563e7abf81SAndi Shyti 
14573e7abf81SAndi Shyti 	/* Setting Fixed Bias */
14583e7abf81SAndi Shyti 	val = VLV_OVERRIDE_EN | VLV_SOC_TDP_EN | VLV_BIAS_CPU_125_SOC_875;
14593e7abf81SAndi Shyti 	vlv_punit_write(i915, VLV_TURBO_SOC_OVERRIDE, val);
14603e7abf81SAndi Shyti 
14613e7abf81SAndi Shyti 	val = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
14623e7abf81SAndi Shyti 
14633e7abf81SAndi Shyti 	vlv_punit_put(i915);
14643e7abf81SAndi Shyti 
14653e7abf81SAndi Shyti 	/* RPS code assumes GPLL is used */
14660d4c351aSPankaj Bharadiya 	drm_WARN_ONCE(&i915->drm, (val & GPLLENABLE) == 0,
14670d4c351aSPankaj Bharadiya 		      "GPLL not enabled\n");
14683e7abf81SAndi Shyti 
146901fabda8SLucas De Marchi 	drm_dbg(&i915->drm, "GPLL enabled? %s\n",
147001fabda8SLucas De Marchi 		str_yes_no(val & GPLLENABLE));
1471a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "GPU status: 0x%08x\n", val);
14723e7abf81SAndi Shyti 
14733e7abf81SAndi Shyti 	return rps_reset(rps);
14743e7abf81SAndi Shyti }
14753e7abf81SAndi Shyti 
__ips_gfx_val(struct intel_ips * ips)14763e7abf81SAndi Shyti static unsigned long __ips_gfx_val(struct intel_ips *ips)
14773e7abf81SAndi Shyti {
14783e7abf81SAndi Shyti 	struct intel_rps *rps = container_of(ips, typeof(*rps), ips);
14793e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
1480d08c4e23SVille Syrjälä 	unsigned int t, state1, state2;
14813e7abf81SAndi Shyti 	u32 pxvid, ext_v;
1482d08c4e23SVille Syrjälä 	u64 corr, corr2;
14833e7abf81SAndi Shyti 
14843e7abf81SAndi Shyti 	lockdep_assert_held(&mchdev_lock);
14853e7abf81SAndi Shyti 
14863e7abf81SAndi Shyti 	pxvid = intel_uncore_read(uncore, PXVFREQ(rps->cur_freq));
14873e7abf81SAndi Shyti 	pxvid = (pxvid >> 24) & 0x7f;
14883e7abf81SAndi Shyti 	ext_v = pvid_to_extvid(rps_to_i915(rps), pxvid);
14893e7abf81SAndi Shyti 
14903e7abf81SAndi Shyti 	state1 = ext_v;
14913e7abf81SAndi Shyti 
14923e7abf81SAndi Shyti 	/* Revel in the empirically derived constants */
14933e7abf81SAndi Shyti 
14943e7abf81SAndi Shyti 	/* Correction factor in 1/100000 units */
14953e7abf81SAndi Shyti 	t = ips_mch_val(uncore);
14963e7abf81SAndi Shyti 	if (t > 80)
14973e7abf81SAndi Shyti 		corr = t * 2349 + 135940;
14983e7abf81SAndi Shyti 	else if (t >= 50)
14993e7abf81SAndi Shyti 		corr = t * 964 + 29317;
15003e7abf81SAndi Shyti 	else /* < 50 */
15013e7abf81SAndi Shyti 		corr = t * 301 + 1004;
15023e7abf81SAndi Shyti 
1503d08c4e23SVille Syrjälä 	corr = div_u64(corr * 150142 * state1, 10000) - 78642;
1504d08c4e23SVille Syrjälä 	corr2 = div_u64(corr, 100000) * ips->corr;
15053e7abf81SAndi Shyti 
1506d08c4e23SVille Syrjälä 	state2 = div_u64(corr2 * state1, 10000);
15073e7abf81SAndi Shyti 	state2 /= 100; /* convert to mW */
15083e7abf81SAndi Shyti 
15093e7abf81SAndi Shyti 	__gen5_ips_update(ips);
15103e7abf81SAndi Shyti 
15113e7abf81SAndi Shyti 	return ips->gfx_power + state2;
15123e7abf81SAndi Shyti }
15133e7abf81SAndi Shyti 
has_busy_stats(struct intel_rps * rps)151436d516beSChris Wilson static bool has_busy_stats(struct intel_rps *rps)
151536d516beSChris Wilson {
151636d516beSChris Wilson 	struct intel_engine_cs *engine;
151736d516beSChris Wilson 	enum intel_engine_id id;
151836d516beSChris Wilson 
151936d516beSChris Wilson 	for_each_engine(engine, rps_to_gt(rps), id) {
152036d516beSChris Wilson 		if (!intel_engine_supports_stats(engine))
152136d516beSChris Wilson 			return false;
152236d516beSChris Wilson 	}
152336d516beSChris Wilson 
152436d516beSChris Wilson 	return true;
152536d516beSChris Wilson }
152636d516beSChris Wilson 
intel_rps_enable(struct intel_rps * rps)15273e7abf81SAndi Shyti void intel_rps_enable(struct intel_rps *rps)
15283e7abf81SAndi Shyti {
15293e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
15303e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
15319bad2adbSChris Wilson 	bool enabled = false;
15323e7abf81SAndi Shyti 
15339c878557SChris Wilson 	if (!HAS_RPS(i915))
15349c878557SChris Wilson 		return;
15359c878557SChris Wilson 
15367ba79a67SVinay Belgaumkar 	if (rps_uses_slpc(rps))
15377ba79a67SVinay Belgaumkar 		return;
15387ba79a67SVinay Belgaumkar 
15399c878557SChris Wilson 	intel_gt_check_clock_frequency(rps_to_gt(rps));
15409c878557SChris Wilson 
15413e7abf81SAndi Shyti 	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
15429bad2adbSChris Wilson 	if (rps->max_freq <= rps->min_freq)
15439bad2adbSChris Wilson 		/* leave disabled, no room for dynamic reclocking */;
15449bad2adbSChris Wilson 	else if (IS_CHERRYVIEW(i915))
15459bad2adbSChris Wilson 		enabled = chv_rps_enable(rps);
15463e7abf81SAndi Shyti 	else if (IS_VALLEYVIEW(i915))
15479bad2adbSChris Wilson 		enabled = vlv_rps_enable(rps);
1548c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 9)
15499bad2adbSChris Wilson 		enabled = gen9_rps_enable(rps);
1550c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 8)
15519bad2adbSChris Wilson 		enabled = gen8_rps_enable(rps);
1552c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
15539bad2adbSChris Wilson 		enabled = gen6_rps_enable(rps);
15543e7abf81SAndi Shyti 	else if (IS_IRONLAKE_M(i915))
15559bad2adbSChris Wilson 		enabled = gen5_rps_enable(rps);
15569bad2adbSChris Wilson 	else
1557c816723bSLucas De Marchi 		MISSING_CASE(GRAPHICS_VER(i915));
15583e7abf81SAndi Shyti 	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
15599bad2adbSChris Wilson 	if (!enabled)
15603e7abf81SAndi Shyti 		return;
15613e7abf81SAndi Shyti 
1562555a3224SChris Wilson 	GT_TRACE(rps_to_gt(rps),
1563c2307b7fSTvrtko Ursulin 		 "min:%x, max:%x, freq:[%d, %d], thresholds:[%u, %u]\n",
1564555a3224SChris Wilson 		 rps->min_freq, rps->max_freq,
1565555a3224SChris Wilson 		 intel_gpu_freq(rps, rps->min_freq),
1566c2307b7fSTvrtko Ursulin 		 intel_gpu_freq(rps, rps->max_freq),
1567c2307b7fSTvrtko Ursulin 		 rps->power.up_threshold,
1568c2307b7fSTvrtko Ursulin 		 rps->power.down_threshold);
15693e7abf81SAndi Shyti 
1570555a3224SChris Wilson 	GEM_BUG_ON(rps->max_freq < rps->min_freq);
1571555a3224SChris Wilson 	GEM_BUG_ON(rps->idle_freq > rps->max_freq);
1572555a3224SChris Wilson 
1573555a3224SChris Wilson 	GEM_BUG_ON(rps->efficient_freq < rps->min_freq);
1574555a3224SChris Wilson 	GEM_BUG_ON(rps->efficient_freq > rps->max_freq);
15759bad2adbSChris Wilson 
157636d516beSChris Wilson 	if (has_busy_stats(rps))
157736d516beSChris Wilson 		intel_rps_set_timer(rps);
1578bbd57d16SJosé Roberto de Souza 	else if (GRAPHICS_VER(i915) >= 6 && GRAPHICS_VER(i915) <= 11)
15798e99299aSChris Wilson 		intel_rps_set_interrupts(rps);
15808e99299aSChris Wilson 	else
15818e99299aSChris Wilson 		/* Ironlake currently uses intel_ips.ko */ {}
15828e99299aSChris Wilson 
15839bad2adbSChris Wilson 	intel_rps_set_enabled(rps);
15843e7abf81SAndi Shyti }
15853e7abf81SAndi Shyti 
gen6_rps_disable(struct intel_rps * rps)15863e7abf81SAndi Shyti static void gen6_rps_disable(struct intel_rps *rps)
15873e7abf81SAndi Shyti {
158835cc7f32SChris Wilson 	set(rps_to_uncore(rps), GEN6_RP_CONTROL, 0);
15893e7abf81SAndi Shyti }
15903e7abf81SAndi Shyti 
intel_rps_disable(struct intel_rps * rps)15913e7abf81SAndi Shyti void intel_rps_disable(struct intel_rps *rps)
15923e7abf81SAndi Shyti {
15933e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
15943e7abf81SAndi Shyti 
159568eb42b3SRodrigo Vivi 	if (!intel_rps_is_enabled(rps))
159668eb42b3SRodrigo Vivi 		return;
159768eb42b3SRodrigo Vivi 
15989bad2adbSChris Wilson 	intel_rps_clear_enabled(rps);
15998e99299aSChris Wilson 	intel_rps_clear_interrupts(rps);
160036d516beSChris Wilson 	intel_rps_clear_timer(rps);
16013e7abf81SAndi Shyti 
1602c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) >= 6)
16033e7abf81SAndi Shyti 		gen6_rps_disable(rps);
16043e7abf81SAndi Shyti 	else if (IS_IRONLAKE_M(i915))
16053e7abf81SAndi Shyti 		gen5_rps_disable(rps);
16063e7abf81SAndi Shyti }
16073e7abf81SAndi Shyti 
byt_gpu_freq(struct intel_rps * rps,int val)16083e7abf81SAndi Shyti static int byt_gpu_freq(struct intel_rps *rps, int val)
16093e7abf81SAndi Shyti {
16103e7abf81SAndi Shyti 	/*
16113e7abf81SAndi Shyti 	 * N = val - 0xb7
16123e7abf81SAndi Shyti 	 * Slow = Fast = GPLL ref * N
16133e7abf81SAndi Shyti 	 */
16143e7abf81SAndi Shyti 	return DIV_ROUND_CLOSEST(rps->gpll_ref_freq * (val - 0xb7), 1000);
16153e7abf81SAndi Shyti }
16163e7abf81SAndi Shyti 
byt_freq_opcode(struct intel_rps * rps,int val)16173e7abf81SAndi Shyti static int byt_freq_opcode(struct intel_rps *rps, int val)
16183e7abf81SAndi Shyti {
16193e7abf81SAndi Shyti 	return DIV_ROUND_CLOSEST(1000 * val, rps->gpll_ref_freq) + 0xb7;
16203e7abf81SAndi Shyti }
16213e7abf81SAndi Shyti 
chv_gpu_freq(struct intel_rps * rps,int val)16223e7abf81SAndi Shyti static int chv_gpu_freq(struct intel_rps *rps, int val)
16233e7abf81SAndi Shyti {
16243e7abf81SAndi Shyti 	/*
16253e7abf81SAndi Shyti 	 * N = val / 2
16263e7abf81SAndi Shyti 	 * CU (slow) = CU2x (fast) / 2 = GPLL ref * N / 2
16273e7abf81SAndi Shyti 	 */
16283e7abf81SAndi Shyti 	return DIV_ROUND_CLOSEST(rps->gpll_ref_freq * val, 2 * 2 * 1000);
16293e7abf81SAndi Shyti }
16303e7abf81SAndi Shyti 
chv_freq_opcode(struct intel_rps * rps,int val)16313e7abf81SAndi Shyti static int chv_freq_opcode(struct intel_rps *rps, int val)
16323e7abf81SAndi Shyti {
16333e7abf81SAndi Shyti 	/* CHV needs even values */
16343e7abf81SAndi Shyti 	return DIV_ROUND_CLOSEST(2 * 1000 * val, rps->gpll_ref_freq) * 2;
16353e7abf81SAndi Shyti }
16363e7abf81SAndi Shyti 
intel_gpu_freq(struct intel_rps * rps,int val)16373e7abf81SAndi Shyti int intel_gpu_freq(struct intel_rps *rps, int val)
16383e7abf81SAndi Shyti {
16393e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
16403e7abf81SAndi Shyti 
1641c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) >= 9)
16423e7abf81SAndi Shyti 		return DIV_ROUND_CLOSEST(val * GT_FREQUENCY_MULTIPLIER,
16433e7abf81SAndi Shyti 					 GEN9_FREQ_SCALER);
16443e7abf81SAndi Shyti 	else if (IS_CHERRYVIEW(i915))
16453e7abf81SAndi Shyti 		return chv_gpu_freq(rps, val);
16463e7abf81SAndi Shyti 	else if (IS_VALLEYVIEW(i915))
16473e7abf81SAndi Shyti 		return byt_gpu_freq(rps, val);
1648c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
16493e7abf81SAndi Shyti 		return val * GT_FREQUENCY_MULTIPLIER;
1650e82351e7SVille Syrjälä 	else
1651e82351e7SVille Syrjälä 		return val;
16523e7abf81SAndi Shyti }
16533e7abf81SAndi Shyti 
intel_freq_opcode(struct intel_rps * rps,int val)16543e7abf81SAndi Shyti int intel_freq_opcode(struct intel_rps *rps, int val)
16553e7abf81SAndi Shyti {
16563e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
16573e7abf81SAndi Shyti 
1658c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) >= 9)
16593e7abf81SAndi Shyti 		return DIV_ROUND_CLOSEST(val * GEN9_FREQ_SCALER,
16603e7abf81SAndi Shyti 					 GT_FREQUENCY_MULTIPLIER);
16613e7abf81SAndi Shyti 	else if (IS_CHERRYVIEW(i915))
16623e7abf81SAndi Shyti 		return chv_freq_opcode(rps, val);
16633e7abf81SAndi Shyti 	else if (IS_VALLEYVIEW(i915))
16643e7abf81SAndi Shyti 		return byt_freq_opcode(rps, val);
1665c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
16663e7abf81SAndi Shyti 		return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
1667e82351e7SVille Syrjälä 	else
1668e82351e7SVille Syrjälä 		return val;
16693e7abf81SAndi Shyti }
16703e7abf81SAndi Shyti 
vlv_init_gpll_ref_freq(struct intel_rps * rps)16713e7abf81SAndi Shyti static void vlv_init_gpll_ref_freq(struct intel_rps *rps)
16723e7abf81SAndi Shyti {
16733e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
16743e7abf81SAndi Shyti 
16753e7abf81SAndi Shyti 	rps->gpll_ref_freq =
16763e7abf81SAndi Shyti 		vlv_get_cck_clock(i915, "GPLL ref",
16773e7abf81SAndi Shyti 				  CCK_GPLL_CLOCK_CONTROL,
16783e7abf81SAndi Shyti 				  i915->czclk_freq);
16793e7abf81SAndi Shyti 
1680a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "GPLL reference freq: %d kHz\n",
1681a8fa7c07SWambui Karuga 		rps->gpll_ref_freq);
16823e7abf81SAndi Shyti }
16833e7abf81SAndi Shyti 
vlv_rps_init(struct intel_rps * rps)16843e7abf81SAndi Shyti static void vlv_rps_init(struct intel_rps *rps)
16853e7abf81SAndi Shyti {
16863e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
16873e7abf81SAndi Shyti 
16883e7abf81SAndi Shyti 	vlv_iosf_sb_get(i915,
16893e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_PUNIT) |
16903e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_NC) |
16913e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_CCK));
16923e7abf81SAndi Shyti 
16933e7abf81SAndi Shyti 	vlv_init_gpll_ref_freq(rps);
16943e7abf81SAndi Shyti 
16953e7abf81SAndi Shyti 	rps->max_freq = vlv_rps_max_freq(rps);
16963e7abf81SAndi Shyti 	rps->rp0_freq = rps->max_freq;
1697a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "max GPU freq: %d MHz (%u)\n",
1698a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->max_freq), rps->max_freq);
16993e7abf81SAndi Shyti 
17003e7abf81SAndi Shyti 	rps->efficient_freq = vlv_rps_rpe_freq(rps);
1701a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "RPe GPU freq: %d MHz (%u)\n",
1702a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->efficient_freq), rps->efficient_freq);
17033e7abf81SAndi Shyti 
17043e7abf81SAndi Shyti 	rps->rp1_freq = vlv_rps_guar_freq(rps);
1705a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "RP1(Guar Freq) GPU freq: %d MHz (%u)\n",
1706a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->rp1_freq), rps->rp1_freq);
17073e7abf81SAndi Shyti 
17083e7abf81SAndi Shyti 	rps->min_freq = vlv_rps_min_freq(rps);
1709a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "min GPU freq: %d MHz (%u)\n",
1710a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->min_freq), rps->min_freq);
17113e7abf81SAndi Shyti 
17123e7abf81SAndi Shyti 	vlv_iosf_sb_put(i915,
17133e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_PUNIT) |
17143e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_NC) |
17153e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_CCK));
17163e7abf81SAndi Shyti }
17173e7abf81SAndi Shyti 
chv_rps_init(struct intel_rps * rps)17183e7abf81SAndi Shyti static void chv_rps_init(struct intel_rps *rps)
17193e7abf81SAndi Shyti {
17203e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
17213e7abf81SAndi Shyti 
17223e7abf81SAndi Shyti 	vlv_iosf_sb_get(i915,
17233e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_PUNIT) |
17243e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_NC) |
17253e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_CCK));
17263e7abf81SAndi Shyti 
17273e7abf81SAndi Shyti 	vlv_init_gpll_ref_freq(rps);
17283e7abf81SAndi Shyti 
17293e7abf81SAndi Shyti 	rps->max_freq = chv_rps_max_freq(rps);
17303e7abf81SAndi Shyti 	rps->rp0_freq = rps->max_freq;
1731a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "max GPU freq: %d MHz (%u)\n",
1732a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->max_freq), rps->max_freq);
17333e7abf81SAndi Shyti 
17343e7abf81SAndi Shyti 	rps->efficient_freq = chv_rps_rpe_freq(rps);
1735a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "RPe GPU freq: %d MHz (%u)\n",
1736a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->efficient_freq), rps->efficient_freq);
17373e7abf81SAndi Shyti 
17383e7abf81SAndi Shyti 	rps->rp1_freq = chv_rps_guar_freq(rps);
1739a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "RP1(Guar) GPU freq: %d MHz (%u)\n",
1740a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->rp1_freq), rps->rp1_freq);
17413e7abf81SAndi Shyti 
17423e7abf81SAndi Shyti 	rps->min_freq = chv_rps_min_freq(rps);
1743a8fa7c07SWambui Karuga 	drm_dbg(&i915->drm, "min GPU freq: %d MHz (%u)\n",
1744a8fa7c07SWambui Karuga 		intel_gpu_freq(rps, rps->min_freq), rps->min_freq);
17453e7abf81SAndi Shyti 
17463e7abf81SAndi Shyti 	vlv_iosf_sb_put(i915,
17473e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_PUNIT) |
17483e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_NC) |
17493e7abf81SAndi Shyti 			BIT(VLV_IOSF_SB_CCK));
17503e7abf81SAndi Shyti 
17510d4c351aSPankaj Bharadiya 	drm_WARN_ONCE(&i915->drm, (rps->max_freq | rps->efficient_freq |
17520d4c351aSPankaj Bharadiya 				   rps->rp1_freq | rps->min_freq) & 1,
17533e7abf81SAndi Shyti 		      "Odd GPU freq values\n");
17543e7abf81SAndi Shyti }
17553e7abf81SAndi Shyti 
vlv_c0_read(struct intel_uncore * uncore,struct intel_rps_ei * ei)17563e7abf81SAndi Shyti static void vlv_c0_read(struct intel_uncore *uncore, struct intel_rps_ei *ei)
17573e7abf81SAndi Shyti {
17583e7abf81SAndi Shyti 	ei->ktime = ktime_get_raw();
17593e7abf81SAndi Shyti 	ei->render_c0 = intel_uncore_read(uncore, VLV_RENDER_C0_COUNT);
17603e7abf81SAndi Shyti 	ei->media_c0 = intel_uncore_read(uncore, VLV_MEDIA_C0_COUNT);
17613e7abf81SAndi Shyti }
17623e7abf81SAndi Shyti 
vlv_wa_c0_ei(struct intel_rps * rps,u32 pm_iir)17633e7abf81SAndi Shyti static u32 vlv_wa_c0_ei(struct intel_rps *rps, u32 pm_iir)
17643e7abf81SAndi Shyti {
17653e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
17663e7abf81SAndi Shyti 	const struct intel_rps_ei *prev = &rps->ei;
17673e7abf81SAndi Shyti 	struct intel_rps_ei now;
17683e7abf81SAndi Shyti 	u32 events = 0;
17693e7abf81SAndi Shyti 
17703e7abf81SAndi Shyti 	if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
17713e7abf81SAndi Shyti 		return 0;
17723e7abf81SAndi Shyti 
17733e7abf81SAndi Shyti 	vlv_c0_read(uncore, &now);
17743e7abf81SAndi Shyti 
17753e7abf81SAndi Shyti 	if (prev->ktime) {
17763e7abf81SAndi Shyti 		u64 time, c0;
17773e7abf81SAndi Shyti 		u32 render, media;
17783e7abf81SAndi Shyti 
17793e7abf81SAndi Shyti 		time = ktime_us_delta(now.ktime, prev->ktime);
17803e7abf81SAndi Shyti 
17813e7abf81SAndi Shyti 		time *= rps_to_i915(rps)->czclk_freq;
17823e7abf81SAndi Shyti 
17833e7abf81SAndi Shyti 		/* Workload can be split between render + media,
17843e7abf81SAndi Shyti 		 * e.g. SwapBuffers being blitted in X after being rendered in
17853e7abf81SAndi Shyti 		 * mesa. To account for this we need to combine both engines
17863e7abf81SAndi Shyti 		 * into our activity counter.
17873e7abf81SAndi Shyti 		 */
17883e7abf81SAndi Shyti 		render = now.render_c0 - prev->render_c0;
17893e7abf81SAndi Shyti 		media = now.media_c0 - prev->media_c0;
17903e7abf81SAndi Shyti 		c0 = max(render, media);
17913e7abf81SAndi Shyti 		c0 *= 1000 * 100 << 8; /* to usecs and scale to threshold% */
17923e7abf81SAndi Shyti 
17933e7abf81SAndi Shyti 		if (c0 > time * rps->power.up_threshold)
17943e7abf81SAndi Shyti 			events = GEN6_PM_RP_UP_THRESHOLD;
17953e7abf81SAndi Shyti 		else if (c0 < time * rps->power.down_threshold)
17963e7abf81SAndi Shyti 			events = GEN6_PM_RP_DOWN_THRESHOLD;
17973e7abf81SAndi Shyti 	}
17983e7abf81SAndi Shyti 
17993e7abf81SAndi Shyti 	rps->ei = now;
18003e7abf81SAndi Shyti 	return events;
18013e7abf81SAndi Shyti }
18023e7abf81SAndi Shyti 
rps_work(struct work_struct * work)18033e7abf81SAndi Shyti static void rps_work(struct work_struct *work)
18043e7abf81SAndi Shyti {
18053e7abf81SAndi Shyti 	struct intel_rps *rps = container_of(work, typeof(*rps), work);
18063e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
1807a8fa7c07SWambui Karuga 	struct drm_i915_private *i915 = rps_to_i915(rps);
18083e7abf81SAndi Shyti 	bool client_boost = false;
18093e7abf81SAndi Shyti 	int new_freq, adj, min, max;
18103e7abf81SAndi Shyti 	u32 pm_iir = 0;
18113e7abf81SAndi Shyti 
181203d2c54dSMatt Roper 	spin_lock_irq(gt->irq_lock);
18131ebf7aafSChris Wilson 	pm_iir = fetch_and_zero(&rps->pm_iir) & rps->pm_events;
18143e7abf81SAndi Shyti 	client_boost = atomic_read(&rps->num_waiters);
181503d2c54dSMatt Roper 	spin_unlock_irq(gt->irq_lock);
18163e7abf81SAndi Shyti 
18173e7abf81SAndi Shyti 	/* Make sure we didn't queue anything we're not going to process. */
1818408464b4SChris Wilson 	if (!pm_iir && !client_boost)
18193e7abf81SAndi Shyti 		goto out;
18203e7abf81SAndi Shyti 
18213e7abf81SAndi Shyti 	mutex_lock(&rps->lock);
18229bad2adbSChris Wilson 	if (!intel_rps_is_active(rps)) {
18239bad2adbSChris Wilson 		mutex_unlock(&rps->lock);
18249bad2adbSChris Wilson 		return;
18259bad2adbSChris Wilson 	}
18263e7abf81SAndi Shyti 
18273e7abf81SAndi Shyti 	pm_iir |= vlv_wa_c0_ei(rps, pm_iir);
18283e7abf81SAndi Shyti 
18293e7abf81SAndi Shyti 	adj = rps->last_adj;
18303e7abf81SAndi Shyti 	new_freq = rps->cur_freq;
18313e7abf81SAndi Shyti 	min = rps->min_freq_softlimit;
18323e7abf81SAndi Shyti 	max = rps->max_freq_softlimit;
18333e7abf81SAndi Shyti 	if (client_boost)
18343e7abf81SAndi Shyti 		max = rps->max_freq;
1835555a3224SChris Wilson 
1836555a3224SChris Wilson 	GT_TRACE(gt,
1837555a3224SChris Wilson 		 "pm_iir:%x, client_boost:%s, last:%d, cur:%x, min:%x, max:%x\n",
183801fabda8SLucas De Marchi 		 pm_iir, str_yes_no(client_boost),
1839555a3224SChris Wilson 		 adj, new_freq, min, max);
1840555a3224SChris Wilson 
18413e7abf81SAndi Shyti 	if (client_boost && new_freq < rps->boost_freq) {
18423e7abf81SAndi Shyti 		new_freq = rps->boost_freq;
18433e7abf81SAndi Shyti 		adj = 0;
18443e7abf81SAndi Shyti 	} else if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
18453e7abf81SAndi Shyti 		if (adj > 0)
18463e7abf81SAndi Shyti 			adj *= 2;
18473e7abf81SAndi Shyti 		else /* CHV needs even encode values */
18483e7abf81SAndi Shyti 			adj = IS_CHERRYVIEW(gt->i915) ? 2 : 1;
18493e7abf81SAndi Shyti 
18503e7abf81SAndi Shyti 		if (new_freq >= rps->max_freq_softlimit)
18513e7abf81SAndi Shyti 			adj = 0;
18523e7abf81SAndi Shyti 	} else if (client_boost) {
18533e7abf81SAndi Shyti 		adj = 0;
18543e7abf81SAndi Shyti 	} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
18553e7abf81SAndi Shyti 		if (rps->cur_freq > rps->efficient_freq)
18563e7abf81SAndi Shyti 			new_freq = rps->efficient_freq;
18573e7abf81SAndi Shyti 		else if (rps->cur_freq > rps->min_freq_softlimit)
18583e7abf81SAndi Shyti 			new_freq = rps->min_freq_softlimit;
18593e7abf81SAndi Shyti 		adj = 0;
18603e7abf81SAndi Shyti 	} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
18613e7abf81SAndi Shyti 		if (adj < 0)
18623e7abf81SAndi Shyti 			adj *= 2;
18633e7abf81SAndi Shyti 		else /* CHV needs even encode values */
18643e7abf81SAndi Shyti 			adj = IS_CHERRYVIEW(gt->i915) ? -2 : -1;
18653e7abf81SAndi Shyti 
18663e7abf81SAndi Shyti 		if (new_freq <= rps->min_freq_softlimit)
18673e7abf81SAndi Shyti 			adj = 0;
18683e7abf81SAndi Shyti 	} else { /* unknown event */
18693e7abf81SAndi Shyti 		adj = 0;
18703e7abf81SAndi Shyti 	}
18713e7abf81SAndi Shyti 
18723e7abf81SAndi Shyti 	/*
1873de3b4d93SChris Wilson 	 * sysfs frequency limits may have snuck in while
1874de3b4d93SChris Wilson 	 * servicing the interrupt
18753e7abf81SAndi Shyti 	 */
18763e7abf81SAndi Shyti 	new_freq += adj;
18773e7abf81SAndi Shyti 	new_freq = clamp_t(int, new_freq, min, max);
18783e7abf81SAndi Shyti 
18793e7abf81SAndi Shyti 	if (intel_rps_set(rps, new_freq)) {
1880a8fa7c07SWambui Karuga 		drm_dbg(&i915->drm, "Failed to set new GPU frequency\n");
1881de3b4d93SChris Wilson 		adj = 0;
18823e7abf81SAndi Shyti 	}
1883de3b4d93SChris Wilson 	rps->last_adj = adj;
18843e7abf81SAndi Shyti 
18853e7abf81SAndi Shyti 	mutex_unlock(&rps->lock);
18863e7abf81SAndi Shyti 
18873e7abf81SAndi Shyti out:
188803d2c54dSMatt Roper 	spin_lock_irq(gt->irq_lock);
18893e7abf81SAndi Shyti 	gen6_gt_pm_unmask_irq(gt, rps->pm_events);
189003d2c54dSMatt Roper 	spin_unlock_irq(gt->irq_lock);
18913e7abf81SAndi Shyti }
18923e7abf81SAndi Shyti 
gen11_rps_irq_handler(struct intel_rps * rps,u32 pm_iir)18933e7abf81SAndi Shyti void gen11_rps_irq_handler(struct intel_rps *rps, u32 pm_iir)
18943e7abf81SAndi Shyti {
18953e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
18963e7abf81SAndi Shyti 	const u32 events = rps->pm_events & pm_iir;
18973e7abf81SAndi Shyti 
189803d2c54dSMatt Roper 	lockdep_assert_held(gt->irq_lock);
18993e7abf81SAndi Shyti 
19003e7abf81SAndi Shyti 	if (unlikely(!events))
19013e7abf81SAndi Shyti 		return;
19023e7abf81SAndi Shyti 
1903555a3224SChris Wilson 	GT_TRACE(gt, "irq events:%x\n", events);
1904555a3224SChris Wilson 
19053e7abf81SAndi Shyti 	gen6_gt_pm_mask_irq(gt, events);
19063e7abf81SAndi Shyti 
19073e7abf81SAndi Shyti 	rps->pm_iir |= events;
1908848a4e5cSLuca Coelho 	queue_work(gt->i915->unordered_wq, &rps->work);
19093e7abf81SAndi Shyti }
19103e7abf81SAndi Shyti 
gen6_rps_irq_handler(struct intel_rps * rps,u32 pm_iir)19113e7abf81SAndi Shyti void gen6_rps_irq_handler(struct intel_rps *rps, u32 pm_iir)
19123e7abf81SAndi Shyti {
19133e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
1914408464b4SChris Wilson 	u32 events;
19153e7abf81SAndi Shyti 
19161ebf7aafSChris Wilson 	events = pm_iir & rps->pm_events;
1917408464b4SChris Wilson 	if (events) {
191803d2c54dSMatt Roper 		spin_lock(gt->irq_lock);
1919408464b4SChris Wilson 
1920555a3224SChris Wilson 		GT_TRACE(gt, "irq events:%x\n", events);
1921555a3224SChris Wilson 
1922408464b4SChris Wilson 		gen6_gt_pm_mask_irq(gt, events);
1923408464b4SChris Wilson 		rps->pm_iir |= events;
1924408464b4SChris Wilson 
1925848a4e5cSLuca Coelho 		queue_work(gt->i915->unordered_wq, &rps->work);
192603d2c54dSMatt Roper 		spin_unlock(gt->irq_lock);
19273e7abf81SAndi Shyti 	}
19283e7abf81SAndi Shyti 
1929c816723bSLucas De Marchi 	if (GRAPHICS_VER(gt->i915) >= 8)
19303e7abf81SAndi Shyti 		return;
19313e7abf81SAndi Shyti 
19323e7abf81SAndi Shyti 	if (pm_iir & PM_VEBOX_USER_INTERRUPT)
19330669a6e1SChris Wilson 		intel_engine_cs_irq(gt->engine[VECS0], pm_iir >> 10);
19343e7abf81SAndi Shyti 
19353e7abf81SAndi Shyti 	if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
1936a10234fdSTvrtko Ursulin 		drm_dbg(&rps_to_i915(rps)->drm,
1937a10234fdSTvrtko Ursulin 			"Command parser error, pm_iir 0x%08x\n", pm_iir);
19383e7abf81SAndi Shyti }
19393e7abf81SAndi Shyti 
gen5_rps_irq_handler(struct intel_rps * rps)19403e7abf81SAndi Shyti void gen5_rps_irq_handler(struct intel_rps *rps)
19413e7abf81SAndi Shyti {
19423e7abf81SAndi Shyti 	struct intel_uncore *uncore = rps_to_uncore(rps);
19433e7abf81SAndi Shyti 	u32 busy_up, busy_down, max_avg, min_avg;
19443e7abf81SAndi Shyti 	u8 new_freq;
19453e7abf81SAndi Shyti 
19463e7abf81SAndi Shyti 	spin_lock(&mchdev_lock);
19473e7abf81SAndi Shyti 
19483e7abf81SAndi Shyti 	intel_uncore_write16(uncore,
19493e7abf81SAndi Shyti 			     MEMINTRSTS,
19503e7abf81SAndi Shyti 			     intel_uncore_read(uncore, MEMINTRSTS));
19513e7abf81SAndi Shyti 
19523e7abf81SAndi Shyti 	intel_uncore_write16(uncore, MEMINTRSTS, MEMINT_EVAL_CHG);
19533e7abf81SAndi Shyti 	busy_up = intel_uncore_read(uncore, RCPREVBSYTUPAVG);
19543e7abf81SAndi Shyti 	busy_down = intel_uncore_read(uncore, RCPREVBSYTDNAVG);
19553e7abf81SAndi Shyti 	max_avg = intel_uncore_read(uncore, RCBMAXAVG);
19563e7abf81SAndi Shyti 	min_avg = intel_uncore_read(uncore, RCBMINAVG);
19573e7abf81SAndi Shyti 
19583e7abf81SAndi Shyti 	/* Handle RCS change request from hw */
19593e7abf81SAndi Shyti 	new_freq = rps->cur_freq;
19603e7abf81SAndi Shyti 	if (busy_up > max_avg)
19613e7abf81SAndi Shyti 		new_freq++;
19623e7abf81SAndi Shyti 	else if (busy_down < min_avg)
19633e7abf81SAndi Shyti 		new_freq--;
19643e7abf81SAndi Shyti 	new_freq = clamp(new_freq,
19653e7abf81SAndi Shyti 			 rps->min_freq_softlimit,
19663e7abf81SAndi Shyti 			 rps->max_freq_softlimit);
19673e7abf81SAndi Shyti 
19684ee73792SChris Wilson 	if (new_freq != rps->cur_freq && !__gen5_rps_set(rps, new_freq))
19693e7abf81SAndi Shyti 		rps->cur_freq = new_freq;
19703e7abf81SAndi Shyti 
19713e7abf81SAndi Shyti 	spin_unlock(&mchdev_lock);
19723e7abf81SAndi Shyti }
19733e7abf81SAndi Shyti 
intel_rps_init_early(struct intel_rps * rps)1974a06375a9SChris Wilson void intel_rps_init_early(struct intel_rps *rps)
19753e7abf81SAndi Shyti {
19763e7abf81SAndi Shyti 	mutex_init(&rps->lock);
19773e7abf81SAndi Shyti 	mutex_init(&rps->power.mutex);
19783e7abf81SAndi Shyti 
19793e7abf81SAndi Shyti 	INIT_WORK(&rps->work, rps_work);
198036d516beSChris Wilson 	timer_setup(&rps->timer, rps_timer, 0);
19813e7abf81SAndi Shyti 
19823e7abf81SAndi Shyti 	atomic_set(&rps->num_waiters, 0);
1983a06375a9SChris Wilson }
1984a06375a9SChris Wilson 
intel_rps_init(struct intel_rps * rps)1985a06375a9SChris Wilson void intel_rps_init(struct intel_rps *rps)
1986a06375a9SChris Wilson {
1987a06375a9SChris Wilson 	struct drm_i915_private *i915 = rps_to_i915(rps);
19883e7abf81SAndi Shyti 
19897ba79a67SVinay Belgaumkar 	if (rps_uses_slpc(rps))
19907ba79a67SVinay Belgaumkar 		return;
19917ba79a67SVinay Belgaumkar 
19923e7abf81SAndi Shyti 	if (IS_CHERRYVIEW(i915))
19933e7abf81SAndi Shyti 		chv_rps_init(rps);
19943e7abf81SAndi Shyti 	else if (IS_VALLEYVIEW(i915))
19953e7abf81SAndi Shyti 		vlv_rps_init(rps);
1996c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
19973e7abf81SAndi Shyti 		gen6_rps_init(rps);
19983e7abf81SAndi Shyti 	else if (IS_IRONLAKE_M(i915))
19993e7abf81SAndi Shyti 		gen5_rps_init(rps);
20003e7abf81SAndi Shyti 
20013e7abf81SAndi Shyti 	/* Derive initial user preferences/limits from the hardware limits */
20023e7abf81SAndi Shyti 	rps->max_freq_softlimit = rps->max_freq;
2003fdff0a85SAshutosh Dixit 	rps_to_gt(rps)->defaults.max_freq = rps->max_freq_softlimit;
20043e7abf81SAndi Shyti 	rps->min_freq_softlimit = rps->min_freq;
2005fdff0a85SAshutosh Dixit 	rps_to_gt(rps)->defaults.min_freq = rps->min_freq_softlimit;
20063e7abf81SAndi Shyti 
20073e7abf81SAndi Shyti 	/* After setting max-softlimit, find the overclock max freq */
2008c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) == 6 || IS_IVYBRIDGE(i915) || IS_HASWELL(i915)) {
20093e7abf81SAndi Shyti 		u32 params = 0;
20103e7abf81SAndi Shyti 
2011ee421bb4SAshutosh Dixit 		snb_pcode_read(rps_to_gt(rps)->uncore, GEN6_READ_OC_PARAMS, &params, NULL);
20123e7abf81SAndi Shyti 		if (params & BIT(31)) { /* OC supported */
2013a8fa7c07SWambui Karuga 			drm_dbg(&i915->drm,
2014a8fa7c07SWambui Karuga 				"Overclocking supported, max: %dMHz, overclock: %dMHz\n",
20153e7abf81SAndi Shyti 				(rps->max_freq & 0xff) * 50,
20163e7abf81SAndi Shyti 				(params & 0xff) * 50);
20173e7abf81SAndi Shyti 			rps->max_freq = params & 0xff;
20183e7abf81SAndi Shyti 		}
20193e7abf81SAndi Shyti 	}
20203e7abf81SAndi Shyti 
2021c2307b7fSTvrtko Ursulin 	/* Set default thresholds in % */
2022c2307b7fSTvrtko Ursulin 	rps->power.up_threshold = 95;
2023c1886222STvrtko Ursulin 	rps_to_gt(rps)->defaults.rps_up_threshold = rps->power.up_threshold;
2024c2307b7fSTvrtko Ursulin 	rps->power.down_threshold = 85;
2025c1886222STvrtko Ursulin 	rps_to_gt(rps)->defaults.rps_down_threshold = rps->power.down_threshold;
2026c2307b7fSTvrtko Ursulin 
20273e7abf81SAndi Shyti 	/* Finally allow us to boost to max by default */
20283e7abf81SAndi Shyti 	rps->boost_freq = rps->max_freq;
20293e7abf81SAndi Shyti 	rps->idle_freq = rps->min_freq;
2030043cd2d1SChris Wilson 
2031043cd2d1SChris Wilson 	/* Start in the middle, from here we will autotune based on workload */
2032043cd2d1SChris Wilson 	rps->cur_freq = rps->efficient_freq;
20333e7abf81SAndi Shyti 
20343e7abf81SAndi Shyti 	rps->pm_intrmsk_mbz = 0;
20353e7abf81SAndi Shyti 
20363e7abf81SAndi Shyti 	/*
20373e7abf81SAndi Shyti 	 * SNB,IVB,HSW can while VLV,CHV may hard hang on looping batchbuffer
20383e7abf81SAndi Shyti 	 * if GEN6_PM_UP_EI_EXPIRED is masked.
20393e7abf81SAndi Shyti 	 *
20403e7abf81SAndi Shyti 	 * TODO: verify if this can be reproduced on VLV,CHV.
20413e7abf81SAndi Shyti 	 */
2042c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) <= 7)
20433e7abf81SAndi Shyti 		rps->pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED;
20443e7abf81SAndi Shyti 
2045c816723bSLucas De Marchi 	if (GRAPHICS_VER(i915) >= 8 && GRAPHICS_VER(i915) < 11)
20463e7abf81SAndi Shyti 		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
2047933864afSMatthew Brost 
2048933864afSMatthew Brost 	/* GuC needs ARAT expired interrupt unmasked */
2049933864afSMatthew Brost 	if (intel_uc_uses_guc_submission(&rps_to_gt(rps)->uc))
2050933864afSMatthew Brost 		rps->pm_intrmsk_mbz |= ARAT_EXPIRED_INTRMSK;
2051389b7f00SChris Wilson }
20528e99299aSChris Wilson 
intel_rps_sanitize(struct intel_rps * rps)2053389b7f00SChris Wilson void intel_rps_sanitize(struct intel_rps *rps)
2054389b7f00SChris Wilson {
20557ba79a67SVinay Belgaumkar 	if (rps_uses_slpc(rps))
20567ba79a67SVinay Belgaumkar 		return;
20577ba79a67SVinay Belgaumkar 
2058c816723bSLucas De Marchi 	if (GRAPHICS_VER(rps_to_i915(rps)) >= 6)
20598e99299aSChris Wilson 		rps_disable_interrupts(rps);
20603e7abf81SAndi Shyti }
20613e7abf81SAndi Shyti 
intel_rps_read_rpstat(struct intel_rps * rps)206201b8c2e6SDon Hiatt u32 intel_rps_read_rpstat(struct intel_rps *rps)
206301b8c2e6SDon Hiatt {
206401b8c2e6SDon Hiatt 	struct drm_i915_private *i915 = rps_to_i915(rps);
206501b8c2e6SDon Hiatt 	i915_reg_t rpstat;
206601b8c2e6SDon Hiatt 
206701b8c2e6SDon Hiatt 	rpstat = (GRAPHICS_VER(i915) >= 12) ? GEN12_RPSTAT1 : GEN6_RPSTAT1;
206801b8c2e6SDon Hiatt 
206901b8c2e6SDon Hiatt 	return intel_uncore_read(rps_to_gt(rps)->uncore, rpstat);
207001b8c2e6SDon Hiatt }
207101b8c2e6SDon Hiatt 
intel_rps_get_cagf(struct intel_rps * rps,u32 rpstat)207244df42e6SAshutosh Dixit static u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat)
20733e7abf81SAndi Shyti {
20743e7abf81SAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
20753e7abf81SAndi Shyti 	u32 cagf;
20763e7abf81SAndi Shyti 
207722009b6dSBadal Nilawar 	if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
207822009b6dSBadal Nilawar 		cagf = REG_FIELD_GET(MTL_CAGF_MASK, rpstat);
207922009b6dSBadal Nilawar 	else if (GRAPHICS_VER(i915) >= 12)
208001b8c2e6SDon Hiatt 		cagf = REG_FIELD_GET(GEN12_CAGF_MASK, rpstat);
208101b8c2e6SDon Hiatt 	else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
20822c0a284cSAshutosh Dixit 		cagf = REG_FIELD_GET(RPE_MASK, rpstat);
2083c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 9)
20842c0a284cSAshutosh Dixit 		cagf = REG_FIELD_GET(GEN9_CAGF_MASK, rpstat);
20853e7abf81SAndi Shyti 	else if (IS_HASWELL(i915) || IS_BROADWELL(i915))
20862c0a284cSAshutosh Dixit 		cagf = REG_FIELD_GET(HSW_CAGF_MASK, rpstat);
2087c816723bSLucas De Marchi 	else if (GRAPHICS_VER(i915) >= 6)
20882c0a284cSAshutosh Dixit 		cagf = REG_FIELD_GET(GEN6_CAGF_MASK, rpstat);
2089e82351e7SVille Syrjälä 	else
20902c0a284cSAshutosh Dixit 		cagf = gen5_invert_freq(rps, REG_FIELD_GET(MEMSTAT_PSTATE_MASK, rpstat));
20913e7abf81SAndi Shyti 
20923e7abf81SAndi Shyti 	return cagf;
20933e7abf81SAndi Shyti }
20943e7abf81SAndi Shyti 
__read_cagf(struct intel_rps * rps,bool take_fw)209544df42e6SAshutosh Dixit static u32 __read_cagf(struct intel_rps *rps, bool take_fw)
2096e03512edSAndi Shyti {
2097e03512edSAndi Shyti 	struct drm_i915_private *i915 = rps_to_i915(rps);
2098e82351e7SVille Syrjälä 	struct intel_uncore *uncore = rps_to_uncore(rps);
209944df42e6SAshutosh Dixit 	i915_reg_t r = INVALID_MMIO_REG;
2100e03512edSAndi Shyti 	u32 freq;
2101e03512edSAndi Shyti 
210222009b6dSBadal Nilawar 	/*
210322009b6dSBadal Nilawar 	 * For Gen12+ reading freq from HW does not need a forcewake and
210422009b6dSBadal Nilawar 	 * registers will return 0 freq when GT is in RC6
210522009b6dSBadal Nilawar 	 */
210622009b6dSBadal Nilawar 	if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) {
210744df42e6SAshutosh Dixit 		r = MTL_MIRROR_TARGET_WP1;
210822009b6dSBadal Nilawar 	} else if (GRAPHICS_VER(i915) >= 12) {
210944df42e6SAshutosh Dixit 		r = GEN12_RPSTAT1;
211001b8c2e6SDon Hiatt 	} else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
2111e03512edSAndi Shyti 		vlv_punit_get(i915);
2112e03512edSAndi Shyti 		freq = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
2113e03512edSAndi Shyti 		vlv_punit_put(i915);
2114c816723bSLucas De Marchi 	} else if (GRAPHICS_VER(i915) >= 6) {
211544df42e6SAshutosh Dixit 		r = GEN6_RPSTAT1;
2116e03512edSAndi Shyti 	} else {
211744df42e6SAshutosh Dixit 		r = MEMSTAT_ILK;
2118e03512edSAndi Shyti 	}
2119e03512edSAndi Shyti 
212044df42e6SAshutosh Dixit 	if (i915_mmio_reg_valid(r))
212144df42e6SAshutosh Dixit 		freq = take_fw ? intel_uncore_read(uncore, r) : intel_uncore_read_fw(uncore, r);
212244df42e6SAshutosh Dixit 
2123e03512edSAndi Shyti 	return intel_rps_get_cagf(rps, freq);
2124e03512edSAndi Shyti }
2125e03512edSAndi Shyti 
read_cagf(struct intel_rps * rps)212644df42e6SAshutosh Dixit static u32 read_cagf(struct intel_rps *rps)
212744df42e6SAshutosh Dixit {
212844df42e6SAshutosh Dixit 	return __read_cagf(rps, true);
212944df42e6SAshutosh Dixit }
213044df42e6SAshutosh Dixit 
intel_rps_read_actual_frequency(struct intel_rps * rps)2131e03512edSAndi Shyti u32 intel_rps_read_actual_frequency(struct intel_rps *rps)
2132e03512edSAndi Shyti {
21339c878557SChris Wilson 	struct intel_runtime_pm *rpm = rps_to_uncore(rps)->rpm;
2134e03512edSAndi Shyti 	intel_wakeref_t wakeref;
2135e03512edSAndi Shyti 	u32 freq = 0;
2136e03512edSAndi Shyti 
2137e03512edSAndi Shyti 	with_intel_runtime_pm_if_in_use(rpm, wakeref)
2138e03512edSAndi Shyti 		freq = intel_gpu_freq(rps, read_cagf(rps));
2139e03512edSAndi Shyti 
2140e03512edSAndi Shyti 	return freq;
2141e03512edSAndi Shyti }
2142e03512edSAndi Shyti 
intel_rps_read_actual_frequency_fw(struct intel_rps * rps)214344df42e6SAshutosh Dixit u32 intel_rps_read_actual_frequency_fw(struct intel_rps *rps)
214444df42e6SAshutosh Dixit {
214544df42e6SAshutosh Dixit 	return intel_gpu_freq(rps, __read_cagf(rps, false));
214644df42e6SAshutosh Dixit }
214744df42e6SAshutosh Dixit 
intel_rps_read_punit_req(struct intel_rps * rps)214844df42e6SAshutosh Dixit static u32 intel_rps_read_punit_req(struct intel_rps *rps)
214941e5c17eSVinay Belgaumkar {
215041e5c17eSVinay Belgaumkar 	struct intel_uncore *uncore = rps_to_uncore(rps);
2151f25e3908SVinay Belgaumkar 	struct intel_runtime_pm *rpm = rps_to_uncore(rps)->rpm;
2152f25e3908SVinay Belgaumkar 	intel_wakeref_t wakeref;
2153f25e3908SVinay Belgaumkar 	u32 freq = 0;
215441e5c17eSVinay Belgaumkar 
2155f25e3908SVinay Belgaumkar 	with_intel_runtime_pm_if_in_use(rpm, wakeref)
2156f25e3908SVinay Belgaumkar 		freq = intel_uncore_read(uncore, GEN6_RPNSWREQ);
2157f25e3908SVinay Belgaumkar 
2158f25e3908SVinay Belgaumkar 	return freq;
215941e5c17eSVinay Belgaumkar }
216041e5c17eSVinay Belgaumkar 
intel_rps_get_req(u32 pureq)216141e5c17eSVinay Belgaumkar static u32 intel_rps_get_req(u32 pureq)
216241e5c17eSVinay Belgaumkar {
216341e5c17eSVinay Belgaumkar 	u32 req = pureq >> GEN9_SW_REQ_UNSLICE_RATIO_SHIFT;
216441e5c17eSVinay Belgaumkar 
216541e5c17eSVinay Belgaumkar 	return req;
216641e5c17eSVinay Belgaumkar }
216741e5c17eSVinay Belgaumkar 
intel_rps_read_punit_req_frequency(struct intel_rps * rps)216841e5c17eSVinay Belgaumkar u32 intel_rps_read_punit_req_frequency(struct intel_rps *rps)
216941e5c17eSVinay Belgaumkar {
217041e5c17eSVinay Belgaumkar 	u32 freq = intel_rps_get_req(intel_rps_read_punit_req(rps));
217141e5c17eSVinay Belgaumkar 
217241e5c17eSVinay Belgaumkar 	return intel_gpu_freq(rps, freq);
217341e5c17eSVinay Belgaumkar }
217441e5c17eSVinay Belgaumkar 
intel_rps_get_requested_frequency(struct intel_rps * rps)217541e5c17eSVinay Belgaumkar u32 intel_rps_get_requested_frequency(struct intel_rps *rps)
217641e5c17eSVinay Belgaumkar {
217741e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
217841e5c17eSVinay Belgaumkar 		return intel_rps_read_punit_req_frequency(rps);
217941e5c17eSVinay Belgaumkar 	else
218041e5c17eSVinay Belgaumkar 		return intel_gpu_freq(rps, rps->cur_freq);
218141e5c17eSVinay Belgaumkar }
218241e5c17eSVinay Belgaumkar 
intel_rps_get_max_frequency(struct intel_rps * rps)218341e5c17eSVinay Belgaumkar u32 intel_rps_get_max_frequency(struct intel_rps *rps)
218441e5c17eSVinay Belgaumkar {
218541e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
218641e5c17eSVinay Belgaumkar 
218741e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
218841e5c17eSVinay Belgaumkar 		return slpc->max_freq_softlimit;
218941e5c17eSVinay Belgaumkar 	else
219041e5c17eSVinay Belgaumkar 		return intel_gpu_freq(rps, rps->max_freq_softlimit);
219141e5c17eSVinay Belgaumkar }
219241e5c17eSVinay Belgaumkar 
2193018a7bdbSRodrigo Vivi /**
2194018a7bdbSRodrigo Vivi  * intel_rps_get_max_raw_freq - returns the max frequency in some raw format.
2195018a7bdbSRodrigo Vivi  * @rps: the intel_rps structure
2196018a7bdbSRodrigo Vivi  *
2197018a7bdbSRodrigo Vivi  * Returns the max frequency in a raw format. In newer platforms raw is in
2198018a7bdbSRodrigo Vivi  * units of 50 MHz.
2199018a7bdbSRodrigo Vivi  */
intel_rps_get_max_raw_freq(struct intel_rps * rps)2200018a7bdbSRodrigo Vivi u32 intel_rps_get_max_raw_freq(struct intel_rps *rps)
2201018a7bdbSRodrigo Vivi {
2202018a7bdbSRodrigo Vivi 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
2203018a7bdbSRodrigo Vivi 	u32 freq;
2204018a7bdbSRodrigo Vivi 
2205018a7bdbSRodrigo Vivi 	if (rps_uses_slpc(rps)) {
2206018a7bdbSRodrigo Vivi 		return DIV_ROUND_CLOSEST(slpc->rp0_freq,
2207018a7bdbSRodrigo Vivi 					 GT_FREQUENCY_MULTIPLIER);
2208018a7bdbSRodrigo Vivi 	} else {
2209018a7bdbSRodrigo Vivi 		freq = rps->max_freq;
2210018a7bdbSRodrigo Vivi 		if (GRAPHICS_VER(rps_to_i915(rps)) >= 9) {
2211018a7bdbSRodrigo Vivi 			/* Convert GT frequency to 50 MHz units */
2212018a7bdbSRodrigo Vivi 			freq /= GEN9_FREQ_SCALER;
2213018a7bdbSRodrigo Vivi 		}
2214018a7bdbSRodrigo Vivi 		return freq;
2215018a7bdbSRodrigo Vivi 	}
2216018a7bdbSRodrigo Vivi }
2217018a7bdbSRodrigo Vivi 
intel_rps_get_rp0_frequency(struct intel_rps * rps)221841e5c17eSVinay Belgaumkar u32 intel_rps_get_rp0_frequency(struct intel_rps *rps)
221941e5c17eSVinay Belgaumkar {
222041e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
222141e5c17eSVinay Belgaumkar 
222241e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
222341e5c17eSVinay Belgaumkar 		return slpc->rp0_freq;
222441e5c17eSVinay Belgaumkar 	else
222541e5c17eSVinay Belgaumkar 		return intel_gpu_freq(rps, rps->rp0_freq);
222641e5c17eSVinay Belgaumkar }
222741e5c17eSVinay Belgaumkar 
intel_rps_get_rp1_frequency(struct intel_rps * rps)222841e5c17eSVinay Belgaumkar u32 intel_rps_get_rp1_frequency(struct intel_rps *rps)
222941e5c17eSVinay Belgaumkar {
223041e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
223141e5c17eSVinay Belgaumkar 
223241e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
223341e5c17eSVinay Belgaumkar 		return slpc->rp1_freq;
223441e5c17eSVinay Belgaumkar 	else
223541e5c17eSVinay Belgaumkar 		return intel_gpu_freq(rps, rps->rp1_freq);
223641e5c17eSVinay Belgaumkar }
223741e5c17eSVinay Belgaumkar 
intel_rps_get_rpn_frequency(struct intel_rps * rps)223841e5c17eSVinay Belgaumkar u32 intel_rps_get_rpn_frequency(struct intel_rps *rps)
223941e5c17eSVinay Belgaumkar {
224041e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
224141e5c17eSVinay Belgaumkar 
224241e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
224341e5c17eSVinay Belgaumkar 		return slpc->min_freq;
224441e5c17eSVinay Belgaumkar 	else
224541e5c17eSVinay Belgaumkar 		return intel_gpu_freq(rps, rps->min_freq);
224641e5c17eSVinay Belgaumkar }
224741e5c17eSVinay Belgaumkar 
rps_frequency_dump(struct intel_rps * rps,struct drm_printer * p)224883d495a5SVinay Belgaumkar static void rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p)
2249cf51cc7bSVinay Belgaumkar {
2250cf51cc7bSVinay Belgaumkar 	struct intel_gt *gt = rps_to_gt(rps);
2251cf51cc7bSVinay Belgaumkar 	struct drm_i915_private *i915 = gt->i915;
2252cf51cc7bSVinay Belgaumkar 	struct intel_uncore *uncore = gt->uncore;
2253cf51cc7bSVinay Belgaumkar 	struct intel_rps_freq_caps caps;
2254cf51cc7bSVinay Belgaumkar 	u32 rp_state_limits;
2255cf51cc7bSVinay Belgaumkar 	u32 gt_perf_status;
2256cf51cc7bSVinay Belgaumkar 	u32 rpmodectl, rpinclimit, rpdeclimit;
2257cf51cc7bSVinay Belgaumkar 	u32 rpstat, cagf, reqf;
2258cf51cc7bSVinay Belgaumkar 	u32 rpcurupei, rpcurup, rpprevup;
2259cf51cc7bSVinay Belgaumkar 	u32 rpcurdownei, rpcurdown, rpprevdown;
2260cf51cc7bSVinay Belgaumkar 	u32 rpupei, rpupt, rpdownei, rpdownt;
2261cf51cc7bSVinay Belgaumkar 	u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask;
2262cf51cc7bSVinay Belgaumkar 
2263cf51cc7bSVinay Belgaumkar 	rp_state_limits = intel_uncore_read(uncore, GEN6_RP_STATE_LIMITS);
2264cf51cc7bSVinay Belgaumkar 	gen6_rps_get_freq_caps(rps, &caps);
2265cf51cc7bSVinay Belgaumkar 	if (IS_GEN9_LP(i915))
2266cf51cc7bSVinay Belgaumkar 		gt_perf_status = intel_uncore_read(uncore, BXT_GT_PERF_STATUS);
2267cf51cc7bSVinay Belgaumkar 	else
2268cf51cc7bSVinay Belgaumkar 		gt_perf_status = intel_uncore_read(uncore, GEN6_GT_PERF_STATUS);
2269cf51cc7bSVinay Belgaumkar 
2270cf51cc7bSVinay Belgaumkar 	/* RPSTAT1 is in the GT power well */
2271cf51cc7bSVinay Belgaumkar 	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
2272cf51cc7bSVinay Belgaumkar 
2273cf51cc7bSVinay Belgaumkar 	reqf = intel_uncore_read(uncore, GEN6_RPNSWREQ);
2274cf51cc7bSVinay Belgaumkar 	if (GRAPHICS_VER(i915) >= 9) {
2275cf51cc7bSVinay Belgaumkar 		reqf >>= 23;
2276cf51cc7bSVinay Belgaumkar 	} else {
2277cf51cc7bSVinay Belgaumkar 		reqf &= ~GEN6_TURBO_DISABLE;
2278cf51cc7bSVinay Belgaumkar 		if (IS_HASWELL(i915) || IS_BROADWELL(i915))
2279cf51cc7bSVinay Belgaumkar 			reqf >>= 24;
2280cf51cc7bSVinay Belgaumkar 		else
2281cf51cc7bSVinay Belgaumkar 			reqf >>= 25;
2282cf51cc7bSVinay Belgaumkar 	}
2283cf51cc7bSVinay Belgaumkar 	reqf = intel_gpu_freq(rps, reqf);
2284cf51cc7bSVinay Belgaumkar 
2285cf51cc7bSVinay Belgaumkar 	rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL);
2286cf51cc7bSVinay Belgaumkar 	rpinclimit = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);
2287cf51cc7bSVinay Belgaumkar 	rpdeclimit = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);
2288cf51cc7bSVinay Belgaumkar 
228901b8c2e6SDon Hiatt 	rpstat = intel_rps_read_rpstat(rps);
2290cf51cc7bSVinay Belgaumkar 	rpcurupei = intel_uncore_read(uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK;
2291cf51cc7bSVinay Belgaumkar 	rpcurup = intel_uncore_read(uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK;
2292cf51cc7bSVinay Belgaumkar 	rpprevup = intel_uncore_read(uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK;
2293cf51cc7bSVinay Belgaumkar 	rpcurdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK;
2294cf51cc7bSVinay Belgaumkar 	rpcurdown = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK;
2295cf51cc7bSVinay Belgaumkar 	rpprevdown = intel_uncore_read(uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK;
2296cf51cc7bSVinay Belgaumkar 
2297cf51cc7bSVinay Belgaumkar 	rpupei = intel_uncore_read(uncore, GEN6_RP_UP_EI);
2298cf51cc7bSVinay Belgaumkar 	rpupt = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);
2299cf51cc7bSVinay Belgaumkar 
2300cf51cc7bSVinay Belgaumkar 	rpdownei = intel_uncore_read(uncore, GEN6_RP_DOWN_EI);
2301cf51cc7bSVinay Belgaumkar 	rpdownt = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);
2302cf51cc7bSVinay Belgaumkar 
2303cf51cc7bSVinay Belgaumkar 	cagf = intel_rps_read_actual_frequency(rps);
2304cf51cc7bSVinay Belgaumkar 
2305cf51cc7bSVinay Belgaumkar 	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
2306cf51cc7bSVinay Belgaumkar 
2307cf51cc7bSVinay Belgaumkar 	if (GRAPHICS_VER(i915) >= 11) {
2308cf51cc7bSVinay Belgaumkar 		pm_ier = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE);
2309cf51cc7bSVinay Belgaumkar 		pm_imr = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK);
2310cf51cc7bSVinay Belgaumkar 		/*
2311cf51cc7bSVinay Belgaumkar 		 * The equivalent to the PM ISR & IIR cannot be read
2312cf51cc7bSVinay Belgaumkar 		 * without affecting the current state of the system
2313cf51cc7bSVinay Belgaumkar 		 */
2314cf51cc7bSVinay Belgaumkar 		pm_isr = 0;
2315cf51cc7bSVinay Belgaumkar 		pm_iir = 0;
2316cf51cc7bSVinay Belgaumkar 	} else if (GRAPHICS_VER(i915) >= 8) {
2317cf51cc7bSVinay Belgaumkar 		pm_ier = intel_uncore_read(uncore, GEN8_GT_IER(2));
2318cf51cc7bSVinay Belgaumkar 		pm_imr = intel_uncore_read(uncore, GEN8_GT_IMR(2));
2319cf51cc7bSVinay Belgaumkar 		pm_isr = intel_uncore_read(uncore, GEN8_GT_ISR(2));
2320cf51cc7bSVinay Belgaumkar 		pm_iir = intel_uncore_read(uncore, GEN8_GT_IIR(2));
2321cf51cc7bSVinay Belgaumkar 	} else {
2322cf51cc7bSVinay Belgaumkar 		pm_ier = intel_uncore_read(uncore, GEN6_PMIER);
2323cf51cc7bSVinay Belgaumkar 		pm_imr = intel_uncore_read(uncore, GEN6_PMIMR);
2324cf51cc7bSVinay Belgaumkar 		pm_isr = intel_uncore_read(uncore, GEN6_PMISR);
2325cf51cc7bSVinay Belgaumkar 		pm_iir = intel_uncore_read(uncore, GEN6_PMIIR);
2326cf51cc7bSVinay Belgaumkar 	}
2327cf51cc7bSVinay Belgaumkar 	pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
2328cf51cc7bSVinay Belgaumkar 
2329cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Video Turbo Mode: %s\n",
2330cf51cc7bSVinay Belgaumkar 		   str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO));
2331cf51cc7bSVinay Belgaumkar 	drm_printf(p, "HW control enabled: %s\n",
2332cf51cc7bSVinay Belgaumkar 		   str_yes_no(rpmodectl & GEN6_RP_ENABLE));
2333cf51cc7bSVinay Belgaumkar 	drm_printf(p, "SW control enabled: %s\n",
2334cf51cc7bSVinay Belgaumkar 		   str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE));
2335cf51cc7bSVinay Belgaumkar 
2336cf51cc7bSVinay Belgaumkar 	drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n",
2337cf51cc7bSVinay Belgaumkar 		   pm_ier, pm_imr, pm_mask);
2338cf51cc7bSVinay Belgaumkar 	if (GRAPHICS_VER(i915) <= 10)
2339cf51cc7bSVinay Belgaumkar 		drm_printf(p, "PM ISR=0x%08x IIR=0x%08x\n",
2340cf51cc7bSVinay Belgaumkar 			   pm_isr, pm_iir);
2341cf51cc7bSVinay Belgaumkar 	drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n",
2342cf51cc7bSVinay Belgaumkar 		   rps->pm_intrmsk_mbz);
2343cf51cc7bSVinay Belgaumkar 	drm_printf(p, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
2344cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Render p-state ratio: %d\n",
2345cf51cc7bSVinay Belgaumkar 		   (gt_perf_status & (GRAPHICS_VER(i915) >= 9 ? 0x1ff00 : 0xff00)) >> 8);
2346cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Render p-state VID: %d\n",
2347cf51cc7bSVinay Belgaumkar 		   gt_perf_status & 0xff);
2348cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Render p-state limit: %d\n",
2349cf51cc7bSVinay Belgaumkar 		   rp_state_limits & 0xff);
2350cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RPSTAT1: 0x%08x\n", rpstat);
2351cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RPMODECTL: 0x%08x\n", rpmodectl);
2352cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RPINCLIMIT: 0x%08x\n", rpinclimit);
2353cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RPDECLIMIT: 0x%08x\n", rpdeclimit);
2354cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RPNSWREQ: %dMHz\n", reqf);
2355cf51cc7bSVinay Belgaumkar 	drm_printf(p, "CAGF: %dMHz\n", cagf);
2356cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP CUR UP EI: %d (%lldns)\n",
2357cf51cc7bSVinay Belgaumkar 		   rpcurupei,
2358cf51cc7bSVinay Belgaumkar 		   intel_gt_pm_interval_to_ns(gt, rpcurupei));
2359cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP CUR UP: %d (%lldns)\n",
2360cf51cc7bSVinay Belgaumkar 		   rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup));
2361cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP PREV UP: %d (%lldns)\n",
2362cf51cc7bSVinay Belgaumkar 		   rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup));
2363cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Up threshold: %d%%\n",
2364cf51cc7bSVinay Belgaumkar 		   rps->power.up_threshold);
2365cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP UP EI: %d (%lldns)\n",
2366cf51cc7bSVinay Belgaumkar 		   rpupei, intel_gt_pm_interval_to_ns(gt, rpupei));
2367cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP UP THRESHOLD: %d (%lldns)\n",
2368cf51cc7bSVinay Belgaumkar 		   rpupt, intel_gt_pm_interval_to_ns(gt, rpupt));
2369cf51cc7bSVinay Belgaumkar 
2370cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP CUR DOWN EI: %d (%lldns)\n",
2371cf51cc7bSVinay Belgaumkar 		   rpcurdownei,
2372cf51cc7bSVinay Belgaumkar 		   intel_gt_pm_interval_to_ns(gt, rpcurdownei));
2373cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP CUR DOWN: %d (%lldns)\n",
2374cf51cc7bSVinay Belgaumkar 		   rpcurdown,
2375cf51cc7bSVinay Belgaumkar 		   intel_gt_pm_interval_to_ns(gt, rpcurdown));
2376cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP PREV DOWN: %d (%lldns)\n",
2377cf51cc7bSVinay Belgaumkar 		   rpprevdown,
2378cf51cc7bSVinay Belgaumkar 		   intel_gt_pm_interval_to_ns(gt, rpprevdown));
2379cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Down threshold: %d%%\n",
2380cf51cc7bSVinay Belgaumkar 		   rps->power.down_threshold);
2381cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP DOWN EI: %d (%lldns)\n",
2382cf51cc7bSVinay Belgaumkar 		   rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei));
2383cf51cc7bSVinay Belgaumkar 	drm_printf(p, "RP DOWN THRESHOLD: %d (%lldns)\n",
2384cf51cc7bSVinay Belgaumkar 		   rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt));
2385cf51cc7bSVinay Belgaumkar 
2386cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Lowest (RPN) frequency: %dMHz\n",
2387cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, caps.min_freq));
2388cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Nominal (RP1) frequency: %dMHz\n",
2389cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, caps.rp1_freq));
2390cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n",
2391cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, caps.rp0_freq));
2392cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Max overclocked frequency: %dMHz\n",
2393cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->max_freq));
2394cf51cc7bSVinay Belgaumkar 
2395cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Current freq: %d MHz\n",
2396cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->cur_freq));
2397cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Actual freq: %d MHz\n", cagf);
2398cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Idle freq: %d MHz\n",
2399cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->idle_freq));
2400cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Min freq: %d MHz\n",
2401cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->min_freq));
2402cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Boost freq: %d MHz\n",
2403cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->boost_freq));
2404cf51cc7bSVinay Belgaumkar 	drm_printf(p, "Max freq: %d MHz\n",
2405cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->max_freq));
2406cf51cc7bSVinay Belgaumkar 	drm_printf(p,
2407cf51cc7bSVinay Belgaumkar 		   "efficient (RPe) frequency: %d MHz\n",
2408cf51cc7bSVinay Belgaumkar 		   intel_gpu_freq(rps, rps->efficient_freq));
2409cf51cc7bSVinay Belgaumkar }
2410cf51cc7bSVinay Belgaumkar 
slpc_frequency_dump(struct intel_rps * rps,struct drm_printer * p)241183d495a5SVinay Belgaumkar static void slpc_frequency_dump(struct intel_rps *rps, struct drm_printer *p)
241283d495a5SVinay Belgaumkar {
241383d495a5SVinay Belgaumkar 	struct intel_gt *gt = rps_to_gt(rps);
241483d495a5SVinay Belgaumkar 	struct intel_uncore *uncore = gt->uncore;
241583d495a5SVinay Belgaumkar 	struct intel_rps_freq_caps caps;
241683d495a5SVinay Belgaumkar 	u32 pm_mask;
241783d495a5SVinay Belgaumkar 
241883d495a5SVinay Belgaumkar 	gen6_rps_get_freq_caps(rps, &caps);
241983d495a5SVinay Belgaumkar 	pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK);
242083d495a5SVinay Belgaumkar 
242183d495a5SVinay Belgaumkar 	drm_printf(p, "PM MASK=0x%08x\n", pm_mask);
242283d495a5SVinay Belgaumkar 	drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n",
242383d495a5SVinay Belgaumkar 		   rps->pm_intrmsk_mbz);
242401b8c2e6SDon Hiatt 	drm_printf(p, "RPSTAT1: 0x%08x\n", intel_rps_read_rpstat(rps));
242583d495a5SVinay Belgaumkar 	drm_printf(p, "RPNSWREQ: %dMHz\n", intel_rps_get_requested_frequency(rps));
242683d495a5SVinay Belgaumkar 	drm_printf(p, "Lowest (RPN) frequency: %dMHz\n",
242783d495a5SVinay Belgaumkar 		   intel_gpu_freq(rps, caps.min_freq));
242883d495a5SVinay Belgaumkar 	drm_printf(p, "Nominal (RP1) frequency: %dMHz\n",
242983d495a5SVinay Belgaumkar 		   intel_gpu_freq(rps, caps.rp1_freq));
243083d495a5SVinay Belgaumkar 	drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n",
243183d495a5SVinay Belgaumkar 		   intel_gpu_freq(rps, caps.rp0_freq));
243283d495a5SVinay Belgaumkar 	drm_printf(p, "Current freq: %d MHz\n",
243383d495a5SVinay Belgaumkar 		   intel_rps_get_requested_frequency(rps));
243483d495a5SVinay Belgaumkar 	drm_printf(p, "Actual freq: %d MHz\n",
243583d495a5SVinay Belgaumkar 		   intel_rps_read_actual_frequency(rps));
243683d495a5SVinay Belgaumkar 	drm_printf(p, "Min freq: %d MHz\n",
243783d495a5SVinay Belgaumkar 		   intel_rps_get_min_frequency(rps));
243883d495a5SVinay Belgaumkar 	drm_printf(p, "Boost freq: %d MHz\n",
243983d495a5SVinay Belgaumkar 		   intel_rps_get_boost_frequency(rps));
244083d495a5SVinay Belgaumkar 	drm_printf(p, "Max freq: %d MHz\n",
244183d495a5SVinay Belgaumkar 		   intel_rps_get_max_frequency(rps));
244283d495a5SVinay Belgaumkar 	drm_printf(p,
244383d495a5SVinay Belgaumkar 		   "efficient (RPe) frequency: %d MHz\n",
244483d495a5SVinay Belgaumkar 		   intel_gpu_freq(rps, caps.rp1_freq));
244583d495a5SVinay Belgaumkar }
244683d495a5SVinay Belgaumkar 
gen6_rps_frequency_dump(struct intel_rps * rps,struct drm_printer * p)244783d495a5SVinay Belgaumkar void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p)
244883d495a5SVinay Belgaumkar {
244983d495a5SVinay Belgaumkar 	if (rps_uses_slpc(rps))
245083d495a5SVinay Belgaumkar 		return slpc_frequency_dump(rps, p);
245183d495a5SVinay Belgaumkar 	else
245283d495a5SVinay Belgaumkar 		return rps_frequency_dump(rps, p);
245383d495a5SVinay Belgaumkar }
245483d495a5SVinay Belgaumkar 
set_max_freq(struct intel_rps * rps,u32 val)245541e5c17eSVinay Belgaumkar static int set_max_freq(struct intel_rps *rps, u32 val)
245641e5c17eSVinay Belgaumkar {
245741e5c17eSVinay Belgaumkar 	struct drm_i915_private *i915 = rps_to_i915(rps);
245841e5c17eSVinay Belgaumkar 	int ret = 0;
245941e5c17eSVinay Belgaumkar 
246041e5c17eSVinay Belgaumkar 	mutex_lock(&rps->lock);
246141e5c17eSVinay Belgaumkar 
246241e5c17eSVinay Belgaumkar 	val = intel_freq_opcode(rps, val);
246341e5c17eSVinay Belgaumkar 	if (val < rps->min_freq ||
246441e5c17eSVinay Belgaumkar 	    val > rps->max_freq ||
246541e5c17eSVinay Belgaumkar 	    val < rps->min_freq_softlimit) {
246641e5c17eSVinay Belgaumkar 		ret = -EINVAL;
246741e5c17eSVinay Belgaumkar 		goto unlock;
246841e5c17eSVinay Belgaumkar 	}
246941e5c17eSVinay Belgaumkar 
247041e5c17eSVinay Belgaumkar 	if (val > rps->rp0_freq)
247141e5c17eSVinay Belgaumkar 		drm_dbg(&i915->drm, "User requested overclocking to %d\n",
247241e5c17eSVinay Belgaumkar 			intel_gpu_freq(rps, val));
247341e5c17eSVinay Belgaumkar 
247441e5c17eSVinay Belgaumkar 	rps->max_freq_softlimit = val;
247541e5c17eSVinay Belgaumkar 
247641e5c17eSVinay Belgaumkar 	val = clamp_t(int, rps->cur_freq,
247741e5c17eSVinay Belgaumkar 		      rps->min_freq_softlimit,
247841e5c17eSVinay Belgaumkar 		      rps->max_freq_softlimit);
247941e5c17eSVinay Belgaumkar 
248041e5c17eSVinay Belgaumkar 	/*
248141e5c17eSVinay Belgaumkar 	 * We still need *_set_rps to process the new max_delay and
248241e5c17eSVinay Belgaumkar 	 * update the interrupt limits and PMINTRMSK even though
248341e5c17eSVinay Belgaumkar 	 * frequency request may be unchanged.
248441e5c17eSVinay Belgaumkar 	 */
248541e5c17eSVinay Belgaumkar 	intel_rps_set(rps, val);
248641e5c17eSVinay Belgaumkar 
248741e5c17eSVinay Belgaumkar unlock:
248841e5c17eSVinay Belgaumkar 	mutex_unlock(&rps->lock);
248941e5c17eSVinay Belgaumkar 
249041e5c17eSVinay Belgaumkar 	return ret;
249141e5c17eSVinay Belgaumkar }
249241e5c17eSVinay Belgaumkar 
intel_rps_set_max_frequency(struct intel_rps * rps,u32 val)249341e5c17eSVinay Belgaumkar int intel_rps_set_max_frequency(struct intel_rps *rps, u32 val)
249441e5c17eSVinay Belgaumkar {
249541e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
249641e5c17eSVinay Belgaumkar 
249741e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
249841e5c17eSVinay Belgaumkar 		return intel_guc_slpc_set_max_freq(slpc, val);
249941e5c17eSVinay Belgaumkar 	else
250041e5c17eSVinay Belgaumkar 		return set_max_freq(rps, val);
250141e5c17eSVinay Belgaumkar }
250241e5c17eSVinay Belgaumkar 
intel_rps_get_min_frequency(struct intel_rps * rps)250341e5c17eSVinay Belgaumkar u32 intel_rps_get_min_frequency(struct intel_rps *rps)
250441e5c17eSVinay Belgaumkar {
250541e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
250641e5c17eSVinay Belgaumkar 
250741e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
250841e5c17eSVinay Belgaumkar 		return slpc->min_freq_softlimit;
250941e5c17eSVinay Belgaumkar 	else
251041e5c17eSVinay Belgaumkar 		return intel_gpu_freq(rps, rps->min_freq_softlimit);
251141e5c17eSVinay Belgaumkar }
251241e5c17eSVinay Belgaumkar 
2513018a7bdbSRodrigo Vivi /**
2514018a7bdbSRodrigo Vivi  * intel_rps_get_min_raw_freq - returns the min frequency in some raw format.
2515018a7bdbSRodrigo Vivi  * @rps: the intel_rps structure
2516018a7bdbSRodrigo Vivi  *
2517018a7bdbSRodrigo Vivi  * Returns the min frequency in a raw format. In newer platforms raw is in
2518018a7bdbSRodrigo Vivi  * units of 50 MHz.
2519018a7bdbSRodrigo Vivi  */
intel_rps_get_min_raw_freq(struct intel_rps * rps)2520018a7bdbSRodrigo Vivi u32 intel_rps_get_min_raw_freq(struct intel_rps *rps)
2521018a7bdbSRodrigo Vivi {
2522018a7bdbSRodrigo Vivi 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
2523018a7bdbSRodrigo Vivi 	u32 freq;
2524018a7bdbSRodrigo Vivi 
2525018a7bdbSRodrigo Vivi 	if (rps_uses_slpc(rps)) {
2526018a7bdbSRodrigo Vivi 		return DIV_ROUND_CLOSEST(slpc->min_freq,
2527018a7bdbSRodrigo Vivi 					 GT_FREQUENCY_MULTIPLIER);
2528018a7bdbSRodrigo Vivi 	} else {
2529018a7bdbSRodrigo Vivi 		freq = rps->min_freq;
2530018a7bdbSRodrigo Vivi 		if (GRAPHICS_VER(rps_to_i915(rps)) >= 9) {
2531018a7bdbSRodrigo Vivi 			/* Convert GT frequency to 50 MHz units */
2532018a7bdbSRodrigo Vivi 			freq /= GEN9_FREQ_SCALER;
2533018a7bdbSRodrigo Vivi 		}
2534018a7bdbSRodrigo Vivi 		return freq;
2535018a7bdbSRodrigo Vivi 	}
2536018a7bdbSRodrigo Vivi }
2537018a7bdbSRodrigo Vivi 
set_min_freq(struct intel_rps * rps,u32 val)253841e5c17eSVinay Belgaumkar static int set_min_freq(struct intel_rps *rps, u32 val)
253941e5c17eSVinay Belgaumkar {
254041e5c17eSVinay Belgaumkar 	int ret = 0;
254141e5c17eSVinay Belgaumkar 
254241e5c17eSVinay Belgaumkar 	mutex_lock(&rps->lock);
254341e5c17eSVinay Belgaumkar 
254441e5c17eSVinay Belgaumkar 	val = intel_freq_opcode(rps, val);
254541e5c17eSVinay Belgaumkar 	if (val < rps->min_freq ||
254641e5c17eSVinay Belgaumkar 	    val > rps->max_freq ||
254741e5c17eSVinay Belgaumkar 	    val > rps->max_freq_softlimit) {
254841e5c17eSVinay Belgaumkar 		ret = -EINVAL;
254941e5c17eSVinay Belgaumkar 		goto unlock;
255041e5c17eSVinay Belgaumkar 	}
255141e5c17eSVinay Belgaumkar 
255241e5c17eSVinay Belgaumkar 	rps->min_freq_softlimit = val;
255341e5c17eSVinay Belgaumkar 
255441e5c17eSVinay Belgaumkar 	val = clamp_t(int, rps->cur_freq,
255541e5c17eSVinay Belgaumkar 		      rps->min_freq_softlimit,
255641e5c17eSVinay Belgaumkar 		      rps->max_freq_softlimit);
255741e5c17eSVinay Belgaumkar 
255841e5c17eSVinay Belgaumkar 	/*
255941e5c17eSVinay Belgaumkar 	 * We still need *_set_rps to process the new min_delay and
256041e5c17eSVinay Belgaumkar 	 * update the interrupt limits and PMINTRMSK even though
256141e5c17eSVinay Belgaumkar 	 * frequency request may be unchanged.
256241e5c17eSVinay Belgaumkar 	 */
256341e5c17eSVinay Belgaumkar 	intel_rps_set(rps, val);
256441e5c17eSVinay Belgaumkar 
256541e5c17eSVinay Belgaumkar unlock:
256641e5c17eSVinay Belgaumkar 	mutex_unlock(&rps->lock);
256741e5c17eSVinay Belgaumkar 
256841e5c17eSVinay Belgaumkar 	return ret;
256941e5c17eSVinay Belgaumkar }
257041e5c17eSVinay Belgaumkar 
intel_rps_set_min_frequency(struct intel_rps * rps,u32 val)257141e5c17eSVinay Belgaumkar int intel_rps_set_min_frequency(struct intel_rps *rps, u32 val)
257241e5c17eSVinay Belgaumkar {
257341e5c17eSVinay Belgaumkar 	struct intel_guc_slpc *slpc = rps_to_slpc(rps);
257441e5c17eSVinay Belgaumkar 
257541e5c17eSVinay Belgaumkar 	if (rps_uses_slpc(rps))
257641e5c17eSVinay Belgaumkar 		return intel_guc_slpc_set_min_freq(slpc, val);
257741e5c17eSVinay Belgaumkar 	else
257841e5c17eSVinay Belgaumkar 		return set_min_freq(rps, val);
257941e5c17eSVinay Belgaumkar }
258041e5c17eSVinay Belgaumkar 
intel_rps_get_up_threshold(struct intel_rps * rps)2581c1be6162STvrtko Ursulin u8 intel_rps_get_up_threshold(struct intel_rps *rps)
2582c1be6162STvrtko Ursulin {
2583c1be6162STvrtko Ursulin 	return rps->power.up_threshold;
2584c1be6162STvrtko Ursulin }
2585c1be6162STvrtko Ursulin 
rps_set_threshold(struct intel_rps * rps,u8 * threshold,u8 val)2586c1be6162STvrtko Ursulin static int rps_set_threshold(struct intel_rps *rps, u8 *threshold, u8 val)
2587c1be6162STvrtko Ursulin {
2588c1be6162STvrtko Ursulin 	int ret;
2589c1be6162STvrtko Ursulin 
2590c1be6162STvrtko Ursulin 	if (val > 100)
2591c1be6162STvrtko Ursulin 		return -EINVAL;
2592c1be6162STvrtko Ursulin 
2593c1be6162STvrtko Ursulin 	ret = mutex_lock_interruptible(&rps->lock);
2594c1be6162STvrtko Ursulin 	if (ret)
2595c1be6162STvrtko Ursulin 		return ret;
2596c1be6162STvrtko Ursulin 
2597c1be6162STvrtko Ursulin 	if (*threshold == val)
2598c1be6162STvrtko Ursulin 		goto out_unlock;
2599c1be6162STvrtko Ursulin 
2600c1be6162STvrtko Ursulin 	*threshold = val;
2601c1be6162STvrtko Ursulin 
2602c1be6162STvrtko Ursulin 	/* Force reset. */
2603c1be6162STvrtko Ursulin 	rps->last_freq = -1;
2604c1be6162STvrtko Ursulin 	mutex_lock(&rps->power.mutex);
2605c1be6162STvrtko Ursulin 	rps->power.mode = -1;
2606c1be6162STvrtko Ursulin 	mutex_unlock(&rps->power.mutex);
2607c1be6162STvrtko Ursulin 
2608c1be6162STvrtko Ursulin 	intel_rps_set(rps, clamp(rps->cur_freq,
2609c1be6162STvrtko Ursulin 				 rps->min_freq_softlimit,
2610c1be6162STvrtko Ursulin 				 rps->max_freq_softlimit));
2611c1be6162STvrtko Ursulin 
2612c1be6162STvrtko Ursulin out_unlock:
2613c1be6162STvrtko Ursulin 	mutex_unlock(&rps->lock);
2614c1be6162STvrtko Ursulin 
2615c1be6162STvrtko Ursulin 	return ret;
2616c1be6162STvrtko Ursulin }
2617c1be6162STvrtko Ursulin 
intel_rps_set_up_threshold(struct intel_rps * rps,u8 threshold)2618c1be6162STvrtko Ursulin int intel_rps_set_up_threshold(struct intel_rps *rps, u8 threshold)
2619c1be6162STvrtko Ursulin {
2620c1be6162STvrtko Ursulin 	return rps_set_threshold(rps, &rps->power.up_threshold, threshold);
2621c1be6162STvrtko Ursulin }
2622c1be6162STvrtko Ursulin 
intel_rps_get_down_threshold(struct intel_rps * rps)2623c1be6162STvrtko Ursulin u8 intel_rps_get_down_threshold(struct intel_rps *rps)
2624c1be6162STvrtko Ursulin {
2625c1be6162STvrtko Ursulin 	return rps->power.down_threshold;
2626c1be6162STvrtko Ursulin }
2627c1be6162STvrtko Ursulin 
intel_rps_set_down_threshold(struct intel_rps * rps,u8 threshold)2628c1be6162STvrtko Ursulin int intel_rps_set_down_threshold(struct intel_rps *rps, u8 threshold)
2629c1be6162STvrtko Ursulin {
2630c1be6162STvrtko Ursulin 	return rps_set_threshold(rps, &rps->power.down_threshold, threshold);
2631c1be6162STvrtko Ursulin }
2632c1be6162STvrtko Ursulin 
intel_rps_set_manual(struct intel_rps * rps,bool enable)26331c40d40fSVinay Belgaumkar static void intel_rps_set_manual(struct intel_rps *rps, bool enable)
26341c40d40fSVinay Belgaumkar {
26351c40d40fSVinay Belgaumkar 	struct intel_uncore *uncore = rps_to_uncore(rps);
26361c40d40fSVinay Belgaumkar 	u32 state = enable ? GEN9_RPSWCTL_ENABLE : GEN9_RPSWCTL_DISABLE;
26371c40d40fSVinay Belgaumkar 
26381c40d40fSVinay Belgaumkar 	/* Allow punit to process software requests */
26391c40d40fSVinay Belgaumkar 	intel_uncore_write(uncore, GEN6_RP_CONTROL, state);
26401c40d40fSVinay Belgaumkar }
26411c40d40fSVinay Belgaumkar 
intel_rps_raise_unslice(struct intel_rps * rps)26421c40d40fSVinay Belgaumkar void intel_rps_raise_unslice(struct intel_rps *rps)
26431c40d40fSVinay Belgaumkar {
26441c40d40fSVinay Belgaumkar 	struct intel_uncore *uncore = rps_to_uncore(rps);
26451c40d40fSVinay Belgaumkar 
26461c40d40fSVinay Belgaumkar 	mutex_lock(&rps->lock);
26471c40d40fSVinay Belgaumkar 
26481c40d40fSVinay Belgaumkar 	if (rps_uses_slpc(rps)) {
26491c40d40fSVinay Belgaumkar 		/* RP limits have not been initialized yet for SLPC path */
265056758cc4SAshutosh Dixit 		struct intel_rps_freq_caps caps;
265156758cc4SAshutosh Dixit 
265256758cc4SAshutosh Dixit 		gen6_rps_get_freq_caps(rps, &caps);
26531c40d40fSVinay Belgaumkar 
26541c40d40fSVinay Belgaumkar 		intel_rps_set_manual(rps, true);
26551c40d40fSVinay Belgaumkar 		intel_uncore_write(uncore, GEN6_RPNSWREQ,
265656758cc4SAshutosh Dixit 				   ((caps.rp0_freq <<
26571c40d40fSVinay Belgaumkar 				   GEN9_SW_REQ_UNSLICE_RATIO_SHIFT) |
26581c40d40fSVinay Belgaumkar 				   GEN9_IGNORE_SLICE_RATIO));
26591c40d40fSVinay Belgaumkar 		intel_rps_set_manual(rps, false);
26601c40d40fSVinay Belgaumkar 	} else {
26611c40d40fSVinay Belgaumkar 		intel_rps_set(rps, rps->rp0_freq);
26621c40d40fSVinay Belgaumkar 	}
26631c40d40fSVinay Belgaumkar 
26641c40d40fSVinay Belgaumkar 	mutex_unlock(&rps->lock);
26651c40d40fSVinay Belgaumkar }
26661c40d40fSVinay Belgaumkar 
intel_rps_lower_unslice(struct intel_rps * rps)26671c40d40fSVinay Belgaumkar void intel_rps_lower_unslice(struct intel_rps *rps)
26681c40d40fSVinay Belgaumkar {
26691c40d40fSVinay Belgaumkar 	struct intel_uncore *uncore = rps_to_uncore(rps);
26701c40d40fSVinay Belgaumkar 
26711c40d40fSVinay Belgaumkar 	mutex_lock(&rps->lock);
26721c40d40fSVinay Belgaumkar 
26731c40d40fSVinay Belgaumkar 	if (rps_uses_slpc(rps)) {
26741c40d40fSVinay Belgaumkar 		/* RP limits have not been initialized yet for SLPC path */
267556758cc4SAshutosh Dixit 		struct intel_rps_freq_caps caps;
267656758cc4SAshutosh Dixit 
267756758cc4SAshutosh Dixit 		gen6_rps_get_freq_caps(rps, &caps);
26781c40d40fSVinay Belgaumkar 
26791c40d40fSVinay Belgaumkar 		intel_rps_set_manual(rps, true);
26801c40d40fSVinay Belgaumkar 		intel_uncore_write(uncore, GEN6_RPNSWREQ,
268156758cc4SAshutosh Dixit 				   ((caps.min_freq <<
26821c40d40fSVinay Belgaumkar 				   GEN9_SW_REQ_UNSLICE_RATIO_SHIFT) |
26831c40d40fSVinay Belgaumkar 				   GEN9_IGNORE_SLICE_RATIO));
26841c40d40fSVinay Belgaumkar 		intel_rps_set_manual(rps, false);
26851c40d40fSVinay Belgaumkar 	} else {
26861c40d40fSVinay Belgaumkar 		intel_rps_set(rps, rps->min_freq);
26871c40d40fSVinay Belgaumkar 	}
26881c40d40fSVinay Belgaumkar 
26891c40d40fSVinay Belgaumkar 	mutex_unlock(&rps->lock);
26901c40d40fSVinay Belgaumkar }
26911c40d40fSVinay Belgaumkar 
rps_read_mmio(struct intel_rps * rps,i915_reg_t reg32)2692fa68bff7SSujaritha Sundaresan static u32 rps_read_mmio(struct intel_rps *rps, i915_reg_t reg32)
2693fa68bff7SSujaritha Sundaresan {
2694fa68bff7SSujaritha Sundaresan 	struct intel_gt *gt = rps_to_gt(rps);
2695fa68bff7SSujaritha Sundaresan 	intel_wakeref_t wakeref;
2696fa68bff7SSujaritha Sundaresan 	u32 val;
2697fa68bff7SSujaritha Sundaresan 
2698fa68bff7SSujaritha Sundaresan 	with_intel_runtime_pm(gt->uncore->rpm, wakeref)
2699fa68bff7SSujaritha Sundaresan 		val = intel_uncore_read(gt->uncore, reg32);
2700fa68bff7SSujaritha Sundaresan 
2701fa68bff7SSujaritha Sundaresan 	return val;
2702fa68bff7SSujaritha Sundaresan }
2703fa68bff7SSujaritha Sundaresan 
rps_read_mask_mmio(struct intel_rps * rps,i915_reg_t reg32,u32 mask)2704fa68bff7SSujaritha Sundaresan bool rps_read_mask_mmio(struct intel_rps *rps,
2705fa68bff7SSujaritha Sundaresan 			i915_reg_t reg32, u32 mask)
2706fa68bff7SSujaritha Sundaresan {
2707fa68bff7SSujaritha Sundaresan 	return rps_read_mmio(rps, reg32) & mask;
2708fa68bff7SSujaritha Sundaresan }
2709fa68bff7SSujaritha Sundaresan 
27103e7abf81SAndi Shyti /* External interface for intel_ips.ko */
27113e7abf81SAndi Shyti 
27123e7abf81SAndi Shyti static struct drm_i915_private __rcu *ips_mchdev;
27133e7abf81SAndi Shyti 
2714445a1b81SLee Jones /*
27153e7abf81SAndi Shyti  * Tells the intel_ips driver that the i915 driver is now loaded, if
27163e7abf81SAndi Shyti  * IPS got loaded first.
27173e7abf81SAndi Shyti  *
27183e7abf81SAndi Shyti  * This awkward dance is so that neither module has to depend on the
27193e7abf81SAndi Shyti  * other in order for IPS to do the appropriate communication of
27203e7abf81SAndi Shyti  * GPU turbo limits to i915.
27213e7abf81SAndi Shyti  */
27223e7abf81SAndi Shyti static void
ips_ping_for_i915_load(void)27233e7abf81SAndi Shyti ips_ping_for_i915_load(void)
27243e7abf81SAndi Shyti {
27253e7abf81SAndi Shyti 	void (*link)(void);
27263e7abf81SAndi Shyti 
27273e7abf81SAndi Shyti 	link = symbol_get(ips_link_to_i915_driver);
27283e7abf81SAndi Shyti 	if (link) {
27293e7abf81SAndi Shyti 		link();
27303e7abf81SAndi Shyti 		symbol_put(ips_link_to_i915_driver);
27313e7abf81SAndi Shyti 	}
27323e7abf81SAndi Shyti }
27333e7abf81SAndi Shyti 
intel_rps_driver_register(struct intel_rps * rps)27343e7abf81SAndi Shyti void intel_rps_driver_register(struct intel_rps *rps)
27353e7abf81SAndi Shyti {
27363e7abf81SAndi Shyti 	struct intel_gt *gt = rps_to_gt(rps);
27373e7abf81SAndi Shyti 
27383e7abf81SAndi Shyti 	/*
27393e7abf81SAndi Shyti 	 * We only register the i915 ips part with intel-ips once everything is
27403e7abf81SAndi Shyti 	 * set up, to avoid intel-ips sneaking in and reading bogus values.
27413e7abf81SAndi Shyti 	 */
2742c816723bSLucas De Marchi 	if (GRAPHICS_VER(gt->i915) == 5) {
2743c0168a3eSChris Wilson 		GEM_BUG_ON(ips_mchdev);
27443e7abf81SAndi Shyti 		rcu_assign_pointer(ips_mchdev, gt->i915);
27453e7abf81SAndi Shyti 		ips_ping_for_i915_load();
27463e7abf81SAndi Shyti 	}
27473e7abf81SAndi Shyti }
27483e7abf81SAndi Shyti 
intel_rps_driver_unregister(struct intel_rps * rps)27493e7abf81SAndi Shyti void intel_rps_driver_unregister(struct intel_rps *rps)
27503e7abf81SAndi Shyti {
2751ad3662e2SChris Wilson 	if (rcu_access_pointer(ips_mchdev) == rps_to_i915(rps))
27523e7abf81SAndi Shyti 		rcu_assign_pointer(ips_mchdev, NULL);
27533e7abf81SAndi Shyti }
27543e7abf81SAndi Shyti 
mchdev_get(void)27553e7abf81SAndi Shyti static struct drm_i915_private *mchdev_get(void)
27563e7abf81SAndi Shyti {
27573e7abf81SAndi Shyti 	struct drm_i915_private *i915;
27583e7abf81SAndi Shyti 
27593e7abf81SAndi Shyti 	rcu_read_lock();
27603e7abf81SAndi Shyti 	i915 = rcu_dereference(ips_mchdev);
27616cb304b3SChris Wilson 	if (i915 && !kref_get_unless_zero(&i915->drm.ref))
27623e7abf81SAndi Shyti 		i915 = NULL;
27633e7abf81SAndi Shyti 	rcu_read_unlock();
27643e7abf81SAndi Shyti 
27653e7abf81SAndi Shyti 	return i915;
27663e7abf81SAndi Shyti }
27673e7abf81SAndi Shyti 
27683e7abf81SAndi Shyti /**
27693e7abf81SAndi Shyti  * i915_read_mch_val - return value for IPS use
27703e7abf81SAndi Shyti  *
27713e7abf81SAndi Shyti  * Calculate and return a value for the IPS driver to use when deciding whether
27723e7abf81SAndi Shyti  * we have thermal and power headroom to increase CPU or GPU power budget.
27733e7abf81SAndi Shyti  */
i915_read_mch_val(void)27743e7abf81SAndi Shyti unsigned long i915_read_mch_val(void)
27753e7abf81SAndi Shyti {
27763e7abf81SAndi Shyti 	struct drm_i915_private *i915;
27773e7abf81SAndi Shyti 	unsigned long chipset_val = 0;
27783e7abf81SAndi Shyti 	unsigned long graphics_val = 0;
27793e7abf81SAndi Shyti 	intel_wakeref_t wakeref;
27803e7abf81SAndi Shyti 
27813e7abf81SAndi Shyti 	i915 = mchdev_get();
27823e7abf81SAndi Shyti 	if (!i915)
27833e7abf81SAndi Shyti 		return 0;
27843e7abf81SAndi Shyti 
27853e7abf81SAndi Shyti 	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
2786c14adcbdSMichał Winiarski 		struct intel_ips *ips = &to_gt(i915)->rps.ips;
27873e7abf81SAndi Shyti 
27883e7abf81SAndi Shyti 		spin_lock_irq(&mchdev_lock);
27893e7abf81SAndi Shyti 		chipset_val = __ips_chipset_val(ips);
27903e7abf81SAndi Shyti 		graphics_val = __ips_gfx_val(ips);
27913e7abf81SAndi Shyti 		spin_unlock_irq(&mchdev_lock);
27923e7abf81SAndi Shyti 	}
27933e7abf81SAndi Shyti 
27943e7abf81SAndi Shyti 	drm_dev_put(&i915->drm);
27953e7abf81SAndi Shyti 	return chipset_val + graphics_val;
27963e7abf81SAndi Shyti }
27973e7abf81SAndi Shyti EXPORT_SYMBOL_GPL(i915_read_mch_val);
27983e7abf81SAndi Shyti 
27993e7abf81SAndi Shyti /**
28003e7abf81SAndi Shyti  * i915_gpu_raise - raise GPU frequency limit
28013e7abf81SAndi Shyti  *
28023e7abf81SAndi Shyti  * Raise the limit; IPS indicates we have thermal headroom.
28033e7abf81SAndi Shyti  */
i915_gpu_raise(void)28043e7abf81SAndi Shyti bool i915_gpu_raise(void)
28053e7abf81SAndi Shyti {
28063e7abf81SAndi Shyti 	struct drm_i915_private *i915;
28073e7abf81SAndi Shyti 	struct intel_rps *rps;
28083e7abf81SAndi Shyti 
28093e7abf81SAndi Shyti 	i915 = mchdev_get();
28103e7abf81SAndi Shyti 	if (!i915)
28113e7abf81SAndi Shyti 		return false;
28123e7abf81SAndi Shyti 
2813c14adcbdSMichał Winiarski 	rps = &to_gt(i915)->rps;
28143e7abf81SAndi Shyti 
28153e7abf81SAndi Shyti 	spin_lock_irq(&mchdev_lock);
28163e7abf81SAndi Shyti 	if (rps->max_freq_softlimit < rps->max_freq)
28173e7abf81SAndi Shyti 		rps->max_freq_softlimit++;
28183e7abf81SAndi Shyti 	spin_unlock_irq(&mchdev_lock);
28193e7abf81SAndi Shyti 
28203e7abf81SAndi Shyti 	drm_dev_put(&i915->drm);
28213e7abf81SAndi Shyti 	return true;
28223e7abf81SAndi Shyti }
28233e7abf81SAndi Shyti EXPORT_SYMBOL_GPL(i915_gpu_raise);
28243e7abf81SAndi Shyti 
28253e7abf81SAndi Shyti /**
28263e7abf81SAndi Shyti  * i915_gpu_lower - lower GPU frequency limit
28273e7abf81SAndi Shyti  *
28283e7abf81SAndi Shyti  * IPS indicates we're close to a thermal limit, so throttle back the GPU
28293e7abf81SAndi Shyti  * frequency maximum.
28303e7abf81SAndi Shyti  */
i915_gpu_lower(void)28313e7abf81SAndi Shyti bool i915_gpu_lower(void)
28323e7abf81SAndi Shyti {
28333e7abf81SAndi Shyti 	struct drm_i915_private *i915;
28343e7abf81SAndi Shyti 	struct intel_rps *rps;
28353e7abf81SAndi Shyti 
28363e7abf81SAndi Shyti 	i915 = mchdev_get();
28373e7abf81SAndi Shyti 	if (!i915)
28383e7abf81SAndi Shyti 		return false;
28393e7abf81SAndi Shyti 
2840c14adcbdSMichał Winiarski 	rps = &to_gt(i915)->rps;
28413e7abf81SAndi Shyti 
28423e7abf81SAndi Shyti 	spin_lock_irq(&mchdev_lock);
28433e7abf81SAndi Shyti 	if (rps->max_freq_softlimit > rps->min_freq)
28443e7abf81SAndi Shyti 		rps->max_freq_softlimit--;
28453e7abf81SAndi Shyti 	spin_unlock_irq(&mchdev_lock);
28463e7abf81SAndi Shyti 
28473e7abf81SAndi Shyti 	drm_dev_put(&i915->drm);
28483e7abf81SAndi Shyti 	return true;
28493e7abf81SAndi Shyti }
28503e7abf81SAndi Shyti EXPORT_SYMBOL_GPL(i915_gpu_lower);
28513e7abf81SAndi Shyti 
28523e7abf81SAndi Shyti /**
28533e7abf81SAndi Shyti  * i915_gpu_busy - indicate GPU business to IPS
28543e7abf81SAndi Shyti  *
28553e7abf81SAndi Shyti  * Tell the IPS driver whether or not the GPU is busy.
28563e7abf81SAndi Shyti  */
i915_gpu_busy(void)28573e7abf81SAndi Shyti bool i915_gpu_busy(void)
28583e7abf81SAndi Shyti {
28593e7abf81SAndi Shyti 	struct drm_i915_private *i915;
28603e7abf81SAndi Shyti 	bool ret;
28613e7abf81SAndi Shyti 
28623e7abf81SAndi Shyti 	i915 = mchdev_get();
28633e7abf81SAndi Shyti 	if (!i915)
28643e7abf81SAndi Shyti 		return false;
28653e7abf81SAndi Shyti 
2866c14adcbdSMichał Winiarski 	ret = to_gt(i915)->awake;
28673e7abf81SAndi Shyti 
28683e7abf81SAndi Shyti 	drm_dev_put(&i915->drm);
28693e7abf81SAndi Shyti 	return ret;
28703e7abf81SAndi Shyti }
28713e7abf81SAndi Shyti EXPORT_SYMBOL_GPL(i915_gpu_busy);
28723e7abf81SAndi Shyti 
28733e7abf81SAndi Shyti /**
28743e7abf81SAndi Shyti  * i915_gpu_turbo_disable - disable graphics turbo
28753e7abf81SAndi Shyti  *
28763e7abf81SAndi Shyti  * Disable graphics turbo by resetting the max frequency and setting the
28773e7abf81SAndi Shyti  * current frequency to the default.
28783e7abf81SAndi Shyti  */
i915_gpu_turbo_disable(void)28793e7abf81SAndi Shyti bool i915_gpu_turbo_disable(void)
28803e7abf81SAndi Shyti {
28813e7abf81SAndi Shyti 	struct drm_i915_private *i915;
28823e7abf81SAndi Shyti 	struct intel_rps *rps;
28833e7abf81SAndi Shyti 	bool ret;
28843e7abf81SAndi Shyti 
28853e7abf81SAndi Shyti 	i915 = mchdev_get();
28863e7abf81SAndi Shyti 	if (!i915)
28873e7abf81SAndi Shyti 		return false;
28883e7abf81SAndi Shyti 
2889c14adcbdSMichał Winiarski 	rps = &to_gt(i915)->rps;
28903e7abf81SAndi Shyti 
28913e7abf81SAndi Shyti 	spin_lock_irq(&mchdev_lock);
28923e7abf81SAndi Shyti 	rps->max_freq_softlimit = rps->min_freq;
2893c14adcbdSMichał Winiarski 	ret = !__gen5_rps_set(&to_gt(i915)->rps, rps->min_freq);
28943e7abf81SAndi Shyti 	spin_unlock_irq(&mchdev_lock);
28953e7abf81SAndi Shyti 
28963e7abf81SAndi Shyti 	drm_dev_put(&i915->drm);
28973e7abf81SAndi Shyti 	return ret;
28983e7abf81SAndi Shyti }
28993e7abf81SAndi Shyti EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
290046495adcSChris Wilson 
290146495adcSChris Wilson #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
290246495adcSChris Wilson #include "selftest_rps.c"
29038ee2c227SVinay Belgaumkar #include "selftest_slpc.c"
290446495adcSChris Wilson #endif
2905