-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drm/i915: Move the IPS code to its own file
IPS is a pretty well isolated feature. Move the relevant code to a separate file from polluting intel_display.c. I stuck to the hsw_ips name since that's what the function were already using, and also to avoid confusion with the ILK "Intelligen Power Sharing"/intel_ips GPU turbo stuff. And let's also do the s/dev_priv/i915/ rename while touching most of the code. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20220209113526.7595-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com>
- Loading branch information
Ville Syrjälä
committed
Feb 9, 2022
1 parent
2feb6b0
commit f3b603d
Showing
6 changed files
with
279 additions
and
239 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
// SPDX-License-Identifier: MIT | ||
/* | ||
* Copyright © 2022 Intel Corporation | ||
*/ | ||
|
||
#include "hsw_ips.h" | ||
#include "i915_drv.h" | ||
#include "i915_reg.h" | ||
#include "intel_de.h" | ||
#include "intel_display_types.h" | ||
#include "intel_pcode.h" | ||
|
||
static void hsw_ips_enable(const struct intel_crtc_state *crtc_state) | ||
{ | ||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); | ||
struct drm_i915_private *i915 = to_i915(crtc->base.dev); | ||
|
||
if (!crtc_state->ips_enabled) | ||
return; | ||
|
||
/* | ||
* We can only enable IPS after we enable a plane and wait for a vblank | ||
* This function is called from post_plane_update, which is run after | ||
* a vblank wait. | ||
*/ | ||
drm_WARN_ON(&i915->drm, | ||
!(crtc_state->active_planes & ~BIT(PLANE_CURSOR))); | ||
|
||
if (IS_BROADWELL(i915)) { | ||
drm_WARN_ON(&i915->drm, | ||
snb_pcode_write(i915, DISPLAY_IPS_CONTROL, | ||
IPS_ENABLE | IPS_PCODE_CONTROL)); | ||
/* | ||
* Quoting Art Runyan: "its not safe to expect any particular | ||
* value in IPS_CTL bit 31 after enabling IPS through the | ||
* mailbox." Moreover, the mailbox may return a bogus state, | ||
* so we need to just enable it and continue on. | ||
*/ | ||
} else { | ||
intel_de_write(i915, IPS_CTL, IPS_ENABLE); | ||
/* | ||
* The bit only becomes 1 in the next vblank, so this wait here | ||
* is essentially intel_wait_for_vblank. If we don't have this | ||
* and don't wait for vblanks until the end of crtc_enable, then | ||
* the HW state readout code will complain that the expected | ||
* IPS_CTL value is not the one we read. | ||
*/ | ||
if (intel_de_wait_for_set(i915, IPS_CTL, IPS_ENABLE, 50)) | ||
drm_err(&i915->drm, | ||
"Timed out waiting for IPS enable\n"); | ||
} | ||
} | ||
|
||
bool hsw_ips_disable(const struct intel_crtc_state *crtc_state) | ||
{ | ||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); | ||
struct drm_i915_private *i915 = to_i915(crtc->base.dev); | ||
bool need_vblank_wait = false; | ||
|
||
if (!crtc_state->ips_enabled) | ||
return need_vblank_wait; | ||
|
||
if (IS_BROADWELL(i915)) { | ||
drm_WARN_ON(&i915->drm, | ||
snb_pcode_write(i915, DISPLAY_IPS_CONTROL, 0)); | ||
/* | ||
* Wait for PCODE to finish disabling IPS. The BSpec specified | ||
* 42ms timeout value leads to occasional timeouts so use 100ms | ||
* instead. | ||
*/ | ||
if (intel_de_wait_for_clear(i915, IPS_CTL, IPS_ENABLE, 100)) | ||
drm_err(&i915->drm, | ||
"Timed out waiting for IPS disable\n"); | ||
} else { | ||
intel_de_write(i915, IPS_CTL, 0); | ||
intel_de_posting_read(i915, IPS_CTL); | ||
} | ||
|
||
/* We need to wait for a vblank before we can disable the plane. */ | ||
need_vblank_wait = true; | ||
|
||
return need_vblank_wait; | ||
} | ||
|
||
static bool hsw_ips_need_disable(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc) | ||
{ | ||
struct drm_i915_private *i915 = to_i915(state->base.dev); | ||
const struct intel_crtc_state *old_crtc_state = | ||
intel_atomic_get_old_crtc_state(state, crtc); | ||
const struct intel_crtc_state *new_crtc_state = | ||
intel_atomic_get_new_crtc_state(state, crtc); | ||
|
||
if (!old_crtc_state->ips_enabled) | ||
return false; | ||
|
||
if (intel_crtc_needs_modeset(new_crtc_state)) | ||
return true; | ||
|
||
/* | ||
* Workaround : Do not read or write the pipe palette/gamma data while | ||
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. | ||
* | ||
* Disable IPS before we program the LUT. | ||
*/ | ||
if (IS_HASWELL(i915) && | ||
(new_crtc_state->uapi.color_mgmt_changed || | ||
new_crtc_state->update_pipe) && | ||
new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) | ||
return true; | ||
|
||
return !new_crtc_state->ips_enabled; | ||
} | ||
|
||
bool hsw_ips_pre_update(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc) | ||
{ | ||
const struct intel_crtc_state *old_crtc_state = | ||
intel_atomic_get_old_crtc_state(state, crtc); | ||
|
||
if (!hsw_ips_need_disable(state, crtc)) | ||
return false; | ||
|
||
return hsw_ips_disable(old_crtc_state); | ||
} | ||
|
||
static bool hsw_ips_need_enable(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc) | ||
{ | ||
struct drm_i915_private *i915 = to_i915(state->base.dev); | ||
const struct intel_crtc_state *old_crtc_state = | ||
intel_atomic_get_old_crtc_state(state, crtc); | ||
const struct intel_crtc_state *new_crtc_state = | ||
intel_atomic_get_new_crtc_state(state, crtc); | ||
|
||
if (!new_crtc_state->ips_enabled) | ||
return false; | ||
|
||
if (intel_crtc_needs_modeset(new_crtc_state)) | ||
return true; | ||
|
||
/* | ||
* Workaround : Do not read or write the pipe palette/gamma data while | ||
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. | ||
* | ||
* Re-enable IPS after the LUT has been programmed. | ||
*/ | ||
if (IS_HASWELL(i915) && | ||
(new_crtc_state->uapi.color_mgmt_changed || | ||
new_crtc_state->update_pipe) && | ||
new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) | ||
return true; | ||
|
||
/* | ||
* We can't read out IPS on broadwell, assume the worst and | ||
* forcibly enable IPS on the first fastset. | ||
*/ | ||
if (new_crtc_state->update_pipe && old_crtc_state->inherited) | ||
return true; | ||
|
||
return !old_crtc_state->ips_enabled; | ||
} | ||
|
||
void hsw_ips_post_update(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc) | ||
{ | ||
const struct intel_crtc_state *new_crtc_state = | ||
intel_atomic_get_new_crtc_state(state, crtc); | ||
|
||
if (!hsw_ips_need_enable(state, crtc)) | ||
return; | ||
|
||
hsw_ips_enable(new_crtc_state); | ||
} | ||
|
||
/* IPS only exists on ULT machines and is tied to pipe A. */ | ||
bool hsw_crtc_supports_ips(struct intel_crtc *crtc) | ||
{ | ||
return HAS_IPS(to_i915(crtc->base.dev)) && crtc->pipe == PIPE_A; | ||
} | ||
|
||
bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state) | ||
{ | ||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); | ||
struct drm_i915_private *i915 = to_i915(crtc->base.dev); | ||
|
||
/* IPS only exists on ULT machines and is tied to pipe A. */ | ||
if (!hsw_crtc_supports_ips(crtc)) | ||
return false; | ||
|
||
if (!i915->params.enable_ips) | ||
return false; | ||
|
||
if (crtc_state->pipe_bpp > 24) | ||
return false; | ||
|
||
/* | ||
* We compare against max which means we must take | ||
* the increased cdclk requirement into account when | ||
* calculating the new cdclk. | ||
* | ||
* Should measure whether using a lower cdclk w/o IPS | ||
*/ | ||
if (IS_BROADWELL(i915) && | ||
crtc_state->pixel_rate > i915->max_cdclk_freq * 95 / 100) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
int hsw_ips_compute_config(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc) | ||
{ | ||
struct drm_i915_private *i915 = to_i915(state->base.dev); | ||
struct intel_crtc_state *crtc_state = | ||
intel_atomic_get_new_crtc_state(state, crtc); | ||
|
||
crtc_state->ips_enabled = false; | ||
|
||
if (!hsw_crtc_state_ips_capable(crtc_state)) | ||
return 0; | ||
|
||
/* | ||
* When IPS gets enabled, the pipe CRC changes. Since IPS gets | ||
* enabled and disabled dynamically based on package C states, | ||
* user space can't make reliable use of the CRCs, so let's just | ||
* completely disable it. | ||
*/ | ||
if (crtc_state->crc_enabled) | ||
return 0; | ||
|
||
/* IPS should be fine as long as at least one plane is enabled. */ | ||
if (!(crtc_state->active_planes & ~BIT(PLANE_CURSOR))) | ||
return 0; | ||
|
||
if (IS_BROADWELL(i915)) { | ||
const struct intel_cdclk_state *cdclk_state; | ||
|
||
cdclk_state = intel_atomic_get_cdclk_state(state); | ||
if (IS_ERR(cdclk_state)) | ||
return PTR_ERR(cdclk_state); | ||
|
||
/* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ | ||
if (crtc_state->pixel_rate > cdclk_state->logical.cdclk * 95 / 100) | ||
return 0; | ||
} | ||
|
||
crtc_state->ips_enabled = true; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* SPDX-License-Identifier: MIT */ | ||
/* | ||
* Copyright © 2022 Intel Corporation | ||
*/ | ||
|
||
#ifndef __HSW_IPS_H__ | ||
#define __HSW_IPS_H__ | ||
|
||
#include <linux/types.h> | ||
|
||
struct intel_atomic_state; | ||
struct intel_crtc; | ||
struct intel_crtc_state; | ||
|
||
bool hsw_ips_disable(const struct intel_crtc_state *crtc_state); | ||
bool hsw_ips_pre_update(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc); | ||
void hsw_ips_post_update(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc); | ||
bool hsw_crtc_supports_ips(struct intel_crtc *crtc); | ||
bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state); | ||
int hsw_ips_compute_config(struct intel_atomic_state *state, | ||
struct intel_crtc *crtc); | ||
|
||
#endif /* __HSW_IPS_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.