Commit 0a073b84 authored by Jesse Barnes's avatar Jesse Barnes Committed by Daniel Vetter

drm/i915: turbo & RC6 support for VLV v7

Uses slightly different interfaces than other platforms.

v2: track actual set freq, not requested (Rohit)
    fix debug prints in init code (Jesse)
v3: don't write sleep reg (Jesse)
    re-add RC6 wake limit write (Ben)
    fixup thresholds to match other platforms (Ben)
    clean up mem freq calculation (Ben)
    clean up debug prints (Ben)
v4: move defines from punit patch (Ville)
v5: remove writes to nonexistent regs (Jesse)
    put RP and RC regs together (Jesse)
    fix RC6 enable (Jesse)
v6: use correct fuse reads from NC (Jesse)
    split out min/max funcs for use in sysfs (Jesse)
    add debugfs & sysfs freq controls (Jesse)
v7: update with Ben's hw_max changes (Jesse)
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Reviewed-by: Ben Widawsky <ben@bwidawsk.net> (v6)
[danvet: Follow checkpatch sugggestion to use min_t to avoid casting
fun.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 855ba3be
...@@ -941,7 +941,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -941,7 +941,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
MEMSTAT_VID_SHIFT); MEMSTAT_VID_SHIFT);
seq_printf(m, "Current P-state: %d\n", seq_printf(m, "Current P-state: %d\n",
(rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
} else if (IS_GEN6(dev) || IS_GEN7(dev)) { } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
...@@ -1009,6 +1009,25 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -1009,6 +1009,25 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
seq_printf(m, "Max overclocked frequency: %dMHz\n", seq_printf(m, "Max overclocked frequency: %dMHz\n",
dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER); dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
} else if (IS_VALLEYVIEW(dev)) {
u32 freq_sts, val;
valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS,
&freq_sts);
seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
valleyview_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val);
seq_printf(m, "max GPU freq: %d MHz\n",
vlv_gpu_freq(dev_priv->mem_freq, val));
valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val);
seq_printf(m, "min GPU freq: %d MHz\n",
vlv_gpu_freq(dev_priv->mem_freq, val));
seq_printf(m, "current GPU freq: %d MHz\n",
vlv_gpu_freq(dev_priv->mem_freq,
(freq_sts >> 8) & 0xff));
} else { } else {
seq_printf(m, "no P-state info available\n"); seq_printf(m, "no P-state info available\n");
} }
...@@ -1812,7 +1831,11 @@ i915_max_freq_get(void *data, u64 *val) ...@@ -1812,7 +1831,11 @@ i915_max_freq_get(void *data, u64 *val)
if (ret) if (ret)
return ret; return ret;
*val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; if (IS_VALLEYVIEW(dev))
*val = vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.max_delay);
else
*val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return 0; return 0;
...@@ -1837,9 +1860,16 @@ i915_max_freq_set(void *data, u64 val) ...@@ -1837,9 +1860,16 @@ i915_max_freq_set(void *data, u64 val)
/* /*
* Turbo will still be enabled, but won't go above the set value. * Turbo will still be enabled, but won't go above the set value.
*/ */
do_div(val, GT_FREQUENCY_MULTIPLIER); if (IS_VALLEYVIEW(dev)) {
dev_priv->rps.max_delay = val; val = vlv_freq_opcode(dev_priv->mem_freq, val);
gen6_set_rps(dev, val); dev_priv->rps.max_delay = val;
gen6_set_rps(dev, val);
} else {
do_div(val, GT_FREQUENCY_MULTIPLIER);
dev_priv->rps.max_delay = val;
gen6_set_rps(dev, val);
}
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return 0; return 0;
...@@ -1863,7 +1893,11 @@ i915_min_freq_get(void *data, u64 *val) ...@@ -1863,7 +1893,11 @@ i915_min_freq_get(void *data, u64 *val)
if (ret) if (ret)
return ret; return ret;
*val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; if (IS_VALLEYVIEW(dev))
*val = vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.min_delay);
else
*val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return 0; return 0;
...@@ -1888,9 +1922,15 @@ i915_min_freq_set(void *data, u64 val) ...@@ -1888,9 +1922,15 @@ i915_min_freq_set(void *data, u64 val)
/* /*
* Turbo will still be enabled, but won't go below the set value. * Turbo will still be enabled, but won't go below the set value.
*/ */
do_div(val, GT_FREQUENCY_MULTIPLIER); if (IS_VALLEYVIEW(dev)) {
dev_priv->rps.min_delay = val; val = vlv_freq_opcode(dev_priv->mem_freq, val);
gen6_set_rps(dev, val); dev_priv->rps.min_delay = val;
valleyview_set_rps(dev, val);
} else {
do_div(val, GT_FREQUENCY_MULTIPLIER);
dev_priv->rps.min_delay = val;
gen6_set_rps(dev, val);
}
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return 0; return 0;
......
...@@ -1856,6 +1856,9 @@ extern void intel_disable_fbc(struct drm_device *dev); ...@@ -1856,6 +1856,9 @@ extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void intel_init_pch_refclk(struct drm_device *dev); extern void intel_init_pch_refclk(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void gen6_set_rps(struct drm_device *dev, u8 val);
extern void valleyview_set_rps(struct drm_device *dev, u8 val);
extern int valleyview_rps_max_freq(struct drm_i915_private *dev_priv);
extern int valleyview_rps_min_freq(struct drm_i915_private *dev_priv);
extern void intel_detect_pch(struct drm_device *dev); extern void intel_detect_pch(struct drm_device *dev);
extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
extern int intel_enable_rc6(const struct drm_device *dev); extern int intel_enable_rc6(const struct drm_device *dev);
...@@ -1887,6 +1890,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) ...@@ -1887,6 +1890,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val)
int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
int vlv_gpu_freq(int ddr_freq, int val); int vlv_gpu_freq(int ddr_freq, int val);
int vlv_freq_opcode(int ddr_freq, int val); int vlv_freq_opcode(int ddr_freq, int val);
......
...@@ -482,7 +482,10 @@ static void gen6_pm_rps_work(struct work_struct *work) ...@@ -482,7 +482,10 @@ static void gen6_pm_rps_work(struct work_struct *work)
*/ */
if (!(new_delay > dev_priv->rps.max_delay || if (!(new_delay > dev_priv->rps.max_delay ||
new_delay < dev_priv->rps.min_delay)) { new_delay < dev_priv->rps.min_delay)) {
gen6_set_rps(dev_priv->dev, new_delay); if (IS_VALLEYVIEW(dev_priv->dev))
valleyview_set_rps(dev_priv->dev, new_delay);
else
gen6_set_rps(dev_priv->dev, new_delay);
} }
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
......
...@@ -4315,6 +4315,7 @@ ...@@ -4315,6 +4315,7 @@
#define GEN6_RC_CTL_RC6_ENABLE (1<<18) #define GEN6_RC_CTL_RC6_ENABLE (1<<18)
#define GEN6_RC_CTL_RC1e_ENABLE (1<<20) #define GEN6_RC_CTL_RC1e_ENABLE (1<<20)
#define GEN6_RC_CTL_RC7_ENABLE (1<<22) #define GEN6_RC_CTL_RC7_ENABLE (1<<22)
#define GEN7_RC_CTL_TO_MODE (1<<28)
#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) #define GEN6_RC_CTL_EI_MODE(x) ((x)<<27)
#define GEN6_RC_CTL_HW_ENABLE (1<<31) #define GEN6_RC_CTL_HW_ENABLE (1<<31)
#define GEN6_RP_DOWN_TIMEOUT 0xA010 #define GEN6_RP_DOWN_TIMEOUT 0xA010
...@@ -4406,12 +4407,32 @@ ...@@ -4406,12 +4407,32 @@
#define IOSF_BAR_SHIFT 1 #define IOSF_BAR_SHIFT 1
#define IOSF_SB_BUSY (1<<0) #define IOSF_SB_BUSY (1<<0)
#define IOSF_PORT_PUNIT 0x4 #define IOSF_PORT_PUNIT 0x4
#define IOSF_PORT_NC 0x11
#define VLV_IOSF_DATA 0x182104 #define VLV_IOSF_DATA 0x182104
#define VLV_IOSF_ADDR 0x182108 #define VLV_IOSF_ADDR 0x182108
#define PUNIT_OPCODE_REG_READ 6 #define PUNIT_OPCODE_REG_READ 6
#define PUNIT_OPCODE_REG_WRITE 7 #define PUNIT_OPCODE_REG_WRITE 7
#define PUNIT_REG_GPU_LFM 0xd3
#define PUNIT_REG_GPU_FREQ_REQ 0xd4
#define PUNIT_REG_GPU_FREQ_STS 0xd8
#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc
#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */
#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */
#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c
#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3
#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8
#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11
#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800
#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34
#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007
#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30
#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27
#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000
#define GEN6_GT_CORE_STATUS 0x138060 #define GEN6_GT_CORE_STATUS 0x138060
#define GEN6_CORE_CPD_STATE_MASK (7<<4) #define GEN6_CORE_CPD_STATE_MASK (7<<4)
#define GEN6_RCn_MASK 7 #define GEN6_RCn_MASK 7
......
...@@ -212,7 +212,10 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, ...@@ -212,7 +212,10 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
int ret; int ret;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; if (IS_VALLEYVIEW(dev_priv->dev))
ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay);
else
ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret); return snprintf(buf, PAGE_SIZE, "%d\n", ret);
...@@ -226,7 +229,10 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute ...@@ -226,7 +229,10 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
int ret; int ret;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; if (IS_VALLEYVIEW(dev_priv->dev))
ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay);
else
ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret); return snprintf(buf, PAGE_SIZE, "%d\n", ret);
...@@ -246,16 +252,25 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, ...@@ -246,16 +252,25 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
if (ret) if (ret)
return ret; return ret;
val /= GT_FREQUENCY_MULTIPLIER;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); if (IS_VALLEYVIEW(dev_priv->dev)) {
hw_max = dev_priv->rps.hw_max; val = vlv_freq_opcode(dev_priv->mem_freq, val);
non_oc_max = (rp_state_cap & 0xff);
hw_min = ((rp_state_cap & 0xff0000) >> 16); hw_max = valleyview_rps_max_freq(dev_priv);
hw_min = valleyview_rps_min_freq(dev_priv);
non_oc_max = hw_max;
} else {
val /= GT_FREQUENCY_MULTIPLIER;
if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = dev_priv->rps.hw_max;
non_oc_max = (rp_state_cap & 0xff);
hw_min = ((rp_state_cap & 0xff0000) >> 16);
}
if (val < hw_min || val > hw_max ||
val < dev_priv->rps.min_delay) {
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return -EINVAL; return -EINVAL;
} }
...@@ -264,8 +279,12 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, ...@@ -264,8 +279,12 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
DRM_DEBUG("User requested overclocking to %d\n", DRM_DEBUG("User requested overclocking to %d\n",
val * GT_FREQUENCY_MULTIPLIER); val * GT_FREQUENCY_MULTIPLIER);
if (dev_priv->rps.cur_delay > val) if (dev_priv->rps.cur_delay > val) {
gen6_set_rps(dev_priv->dev, val); if (IS_VALLEYVIEW(dev_priv->dev))
valleyview_set_rps(dev_priv->dev, val);
else
gen6_set_rps(dev_priv->dev, val);
}
dev_priv->rps.max_delay = val; dev_priv->rps.max_delay = val;
...@@ -282,7 +301,10 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute ...@@ -282,7 +301,10 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
int ret; int ret;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; if (IS_VALLEYVIEW(dev_priv->dev))
ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay);
else
ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret); return snprintf(buf, PAGE_SIZE, "%d\n", ret);
...@@ -302,21 +324,32 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, ...@@ -302,21 +324,32 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
if (ret) if (ret)
return ret; return ret;
val /= GT_FREQUENCY_MULTIPLIER;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); if (IS_VALLEYVIEW(dev)) {
hw_max = dev_priv->rps.hw_max; val = vlv_freq_opcode(dev_priv->mem_freq, val);
hw_min = ((rp_state_cap & 0xff0000) >> 16);
hw_max = valleyview_rps_max_freq(dev_priv);
hw_min = valleyview_rps_min_freq(dev_priv);
} else {
val /= GT_FREQUENCY_MULTIPLIER;
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = dev_priv->rps.hw_max;
hw_min = ((rp_state_cap & 0xff0000) >> 16);
}
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return -EINVAL; return -EINVAL;
} }
if (dev_priv->rps.cur_delay < val) if (dev_priv->rps.cur_delay < val) {
gen6_set_rps(dev_priv->dev, val); if (IS_VALLEYVIEW(dev))
valleyview_set_rps(dev, val);
else
gen6_set_rps(dev_priv->dev, val);
}
dev_priv->rps.min_delay = val; dev_priv->rps.min_delay = val;
......
...@@ -2481,6 +2481,52 @@ void gen6_set_rps(struct drm_device *dev, u8 val) ...@@ -2481,6 +2481,52 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
trace_intel_gpu_freq_change(val * 50); trace_intel_gpu_freq_change(val * 50);
} }
void valleyview_set_rps(struct drm_device *dev, u8 val)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long timeout = jiffies + msecs_to_jiffies(10);
u32 limits = gen6_rps_limits(dev_priv, &val);
u32 pval;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
WARN_ON(val > dev_priv->rps.max_delay);
WARN_ON(val < dev_priv->rps.min_delay);
DRM_DEBUG_DRIVER("gpu freq request from %d to %d\n",
vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.cur_delay),
vlv_gpu_freq(dev_priv->mem_freq, val));
if (val == dev_priv->rps.cur_delay)
return;
valleyview_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
do {
valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
if (time_after(jiffies, timeout)) {
DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
break;
}
udelay(10);
} while (pval & 1);
valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
if ((pval >> 8) != val)
DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n",
val, pval >> 8);
/* Make sure we continue to get interrupts
* until we hit the minimum or maximum frequencies.
*/
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
dev_priv->rps.cur_delay = pval >> 8;
trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val));
}
static void gen6_disable_rps(struct drm_device *dev) static void gen6_disable_rps(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -2742,6 +2788,127 @@ static void gen6_update_ring_freq(struct drm_device *dev) ...@@ -2742,6 +2788,127 @@ static void gen6_update_ring_freq(struct drm_device *dev)
} }
} }
int valleyview_rps_max_freq(struct drm_i915_private *dev_priv)
{
u32 val, rp0;
valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val);
rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT;
/* Clamp to max */
rp0 = min_t(u32, rp0, 0xea);
return rp0;
}
static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
{
u32 val, rpe;
valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val);
rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT;
valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val);
rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5;
return rpe;
}
int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
{
u32 val;
valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val);
return val & 0xff;
}
static void valleyview_enable_rps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
u32 gtfifodbg, val, rpe;
int i;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
if ((gtfifodbg = I915_READ(GTFIFODBG))) {
DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
I915_WRITE(GTFIFODBG, gtfifodbg);
}
gen6_gt_force_wake_get(dev_priv);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
I915_WRITE(GEN6_RP_UP_EI, 66000);
I915_WRITE(GEN6_RP_DOWN_EI, 350000);
I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
I915_WRITE(GEN6_RP_CONTROL,
GEN6_RP_MEDIA_TURBO |
GEN6_RP_MEDIA_HW_NORMAL_MODE |
GEN6_RP_MEDIA_IS_GFX |
GEN6_RP_ENABLE |
GEN6_RP_UP_BUSY_AVG |
GEN6_RP_DOWN_IDLE_CONT);
I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 0x00280000);
I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
for_each_ring(ring, dev_priv, i)
I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350);
/* allows RC6 residency counter to work */
I915_WRITE(0x138104, _MASKED_BIT_ENABLE(0x3));
I915_WRITE(GEN6_RC_CONTROL,
GEN7_RC_CTL_TO_MODE);
valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val);
dev_priv->mem_freq = 800 + (266 * (val >> 6) & 3);
DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no");
DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
DRM_DEBUG_DRIVER("current GPU freq: %d\n",
vlv_gpu_freq(dev_priv->mem_freq, (val >> 8) & 0xff));
dev_priv->rps.cur_delay = (val >> 8) & 0xff;
dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv);
dev_priv->rps.hw_max = dev_priv->rps.max_delay;
DRM_DEBUG_DRIVER("max GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq,
dev_priv->rps.max_delay));
rpe = valleyview_rps_rpe_freq(dev_priv);
DRM_DEBUG_DRIVER("RPe GPU freq: %d\n",
vlv_gpu_freq(dev_priv->mem_freq, rpe));
val = valleyview_rps_min_freq(dev_priv);
DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq,
val));
dev_priv->rps.min_delay = val;
DRM_DEBUG_DRIVER("setting GPU freq to %d\n",
vlv_gpu_freq(dev_priv->mem_freq, rpe));
valleyview_set_rps(dev_priv->dev, rpe);
/* requires MSI enabled */
I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS);
spin_lock_irq(&dev_priv->rps.lock);
WARN_ON(dev_priv->rps.pm_iir != 0);
I915_WRITE(GEN6_PMIMR, 0);
spin_unlock_irq(&dev_priv->rps.lock);
/* enable all PM interrupts */
I915_WRITE(GEN6_PMINTRMSK, 0);
gen6_gt_force_wake_put(dev_priv);
}
void ironlake_teardown_rc6(struct drm_device *dev) void ironlake_teardown_rc6(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -3468,7 +3635,7 @@ void intel_disable_gt_powersave(struct drm_device *dev) ...@@ -3468,7 +3635,7 @@ void intel_disable_gt_powersave(struct drm_device *dev)
if (IS_IRONLAKE_M(dev)) { if (IS_IRONLAKE_M(dev)) {
ironlake_disable_drps(dev); ironlake_disable_drps(dev);
ironlake_disable_rc6(dev); ironlake_disable_rc6(dev);
} else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) { } else if (INTEL_INFO(dev)->gen >= 6) {
cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
gen6_disable_rps(dev); gen6_disable_rps(dev);
...@@ -3484,8 +3651,13 @@ static void intel_gen6_powersave_work(struct work_struct *work) ...@@ -3484,8 +3651,13 @@ static void intel_gen6_powersave_work(struct work_struct *work)
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
gen6_enable_rps(dev);
gen6_update_ring_freq(dev); if (IS_VALLEYVIEW(dev)) {
valleyview_enable_rps(dev);
} else {
gen6_enable_rps(dev);
gen6_update_ring_freq(dev);
}
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
} }
...@@ -3497,7 +3669,7 @@ void intel_enable_gt_powersave(struct drm_device *dev) ...@@ -3497,7 +3669,7 @@ void intel_enable_gt_powersave(struct drm_device *dev)
ironlake_enable_drps(dev); ironlake_enable_drps(dev);
ironlake_enable_rc6(dev); ironlake_enable_rc6(dev);
intel_init_emon(dev); intel_init_emon(dev);
} else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) { } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
/* /*
* PCU communication is slow and this doesn't need to be * PCU communication is slow and this doesn't need to be
* done at any specific time, so do this out of our fast path * done at any specific time, so do this out of our fast path
...@@ -4568,14 +4740,13 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) ...@@ -4568,14 +4740,13 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
return 0; return 0;
} }
static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode,
u8 addr, u32 *val) u8 addr, u32 *val)
{ {
u32 cmd, devfn, port, be, bar; u32 cmd, devfn, be, bar;
bar = 0; bar = 0;
be = 0xf; be = 0xf;
port = IOSF_PORT_PUNIT;
devfn = PCI_DEVFN(2, 0); devfn = PCI_DEVFN(2, 0);
cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
...@@ -4597,7 +4768,7 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, ...@@ -4597,7 +4768,7 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode,
I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd);
if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0,
500)) { 5)) {
DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n",
opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", opcode == PUNIT_OPCODE_REG_READ ? "read" : "write",
addr); addr);
...@@ -4613,12 +4784,20 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, ...@@ -4613,12 +4784,20 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode,
int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
{ {
return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_READ, addr, val); return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ,
addr, val);
} }
int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
{ {
return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_WRITE, addr, &val); return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE,
addr, &val);
}
int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
{
return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ,
addr, val);
} }
int vlv_gpu_freq(int ddr_freq, int val) int vlv_gpu_freq(int ddr_freq, int val)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment