MTL introduces a new way to instruct the PUnit with power and bandwidth requirements of DE. Add the functionality to program the registers and handle waits using interrupts. The current wait time for timeouts is programmed for 10 msecs to factor in the worst case scenarios. Changes made to use REG_BIT for a register that we touched(GEN8_DE_MISC_IER _MMIO). Wa_14016740474 is added which applies to Xe_LPD+ display v2: checkpatch warning fixes, simplify program pmdemand part v3: update to dbufs and pipes values to pmdemand register(stan) Removed the macro usage in update_pmdemand_values() v4: move the pmdemand_pre_plane_update before cdclk update pmdemand_needs_update included cdclk params comparisons pmdemand_state NULL check (Gustavo) pmdemand.o in sorted order in the makefile (Jani) update pmdemand misc irq handler loop (Gustavo) active phys bitmask and programming correction (Gustavo) v5: simplify pmdemand_state structure simplify methods to find active phys and max port clock Timeout in case of previou pmdemand task pending (Gustavo) v6: rebasing updates to max_ddiclk calculations (Gustavo) updates to active_phys count method (Gustavo) v7: use two separate loop to iterate throug old and new crtc states to calculate the active phys (Gustavo) v8: use uniform function names (Gustavo) v9: For phys change iterate through connectors (Imre) Look for change in phys for pmdemand update (Gustavo, Imre) Some more stlying changes (Imre) Update pmdemand state during HW readout/sanitize (Imre) v10: Fix CI checkpatch warnings v11: use correct pmdemand object pointer during hw readout, simplify the check for phys need update (Gustavo) v12: Handle possible non serialize cases (Imre) Initialise also pmdemand params HW readout (Imre) Update active phys mask during sanitize calls (Imre) Check TC/encoder changes to limit connector update (Imre) v13: Check display version before accessing pmdemand functions v14: Move is_serialized to intel_global_state.c simplify update params and other stlying issues (Imre) Bspec: 66451, 64636, 64602, 64603 Cc: Matt Atwood <matthew.s.atwood@intel.com> Cc: Matt Roper <matthew.d.roper@intel.com> Cc: Lucas De Marchi <lucas.demarchi@intel.com> Cc: Gustavo Sousa <gustavo.sousa@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com> Signed-off-by: Mika Kahola <mika.kahola@intel.com> Signed-off-by: Vinod Govindapillai <vinod.govindapillai@intel.com> Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> #v4 Acked-by: Gustavo Sousa <gustavo.sousa@intel.com> #v11 Reviewed-by: Imre Deak <imre.deak@intel.com> [RK: Fixed minor typo in one of the comments. s/qclck_gc/qclk_gv/] Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230606201032.347449-1-vinod.govindapillai@intel.com
269 lines
6.7 KiB
C
269 lines
6.7 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2020 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include "i915_drv.h"
|
|
#include "intel_atomic.h"
|
|
#include "intel_display_types.h"
|
|
#include "intel_global_state.h"
|
|
|
|
static void __intel_atomic_global_state_free(struct kref *kref)
|
|
{
|
|
struct intel_global_state *obj_state =
|
|
container_of(kref, struct intel_global_state, ref);
|
|
struct intel_global_obj *obj = obj_state->obj;
|
|
|
|
obj->funcs->atomic_destroy_state(obj, obj_state);
|
|
}
|
|
|
|
static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
|
|
{
|
|
kref_put(&obj_state->ref, __intel_atomic_global_state_free);
|
|
}
|
|
|
|
static struct intel_global_state *
|
|
intel_atomic_global_state_get(struct intel_global_state *obj_state)
|
|
{
|
|
kref_get(&obj_state->ref);
|
|
|
|
return obj_state;
|
|
}
|
|
|
|
void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv,
|
|
struct intel_global_obj *obj,
|
|
struct intel_global_state *state,
|
|
const struct intel_global_state_funcs *funcs)
|
|
{
|
|
memset(obj, 0, sizeof(*obj));
|
|
|
|
state->obj = obj;
|
|
|
|
kref_init(&state->ref);
|
|
|
|
obj->state = state;
|
|
obj->funcs = funcs;
|
|
list_add_tail(&obj->head, &dev_priv->display.global.obj_list);
|
|
}
|
|
|
|
void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv)
|
|
{
|
|
struct intel_global_obj *obj, *next;
|
|
|
|
list_for_each_entry_safe(obj, next, &dev_priv->display.global.obj_list, head) {
|
|
list_del(&obj->head);
|
|
|
|
drm_WARN_ON(&dev_priv->drm, kref_read(&obj->state->ref) != 1);
|
|
intel_atomic_global_state_put(obj->state);
|
|
}
|
|
}
|
|
|
|
static void assert_global_state_write_locked(struct drm_i915_private *dev_priv)
|
|
{
|
|
struct intel_crtc *crtc;
|
|
|
|
for_each_intel_crtc(&dev_priv->drm, crtc)
|
|
drm_modeset_lock_assert_held(&crtc->base.mutex);
|
|
}
|
|
|
|
static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx,
|
|
struct drm_modeset_lock *lock)
|
|
{
|
|
struct drm_modeset_lock *l;
|
|
|
|
list_for_each_entry(l, &ctx->locked, head) {
|
|
if (lock == l)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void assert_global_state_read_locked(struct intel_atomic_state *state)
|
|
{
|
|
struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx;
|
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
struct intel_crtc *crtc;
|
|
|
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
|
if (modeset_lock_is_held(ctx, &crtc->base.mutex))
|
|
return;
|
|
}
|
|
|
|
drm_WARN(&dev_priv->drm, 1, "Global state not read locked\n");
|
|
}
|
|
|
|
struct intel_global_state *
|
|
intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
|
|
struct intel_global_obj *obj)
|
|
{
|
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
|
int index, num_objs, i;
|
|
size_t size;
|
|
struct __intel_global_objs_state *arr;
|
|
struct intel_global_state *obj_state;
|
|
|
|
for (i = 0; i < state->num_global_objs; i++)
|
|
if (obj == state->global_objs[i].ptr)
|
|
return state->global_objs[i].state;
|
|
|
|
assert_global_state_read_locked(state);
|
|
|
|
num_objs = state->num_global_objs + 1;
|
|
size = sizeof(*state->global_objs) * num_objs;
|
|
arr = krealloc(state->global_objs, size, GFP_KERNEL);
|
|
if (!arr)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
state->global_objs = arr;
|
|
index = state->num_global_objs;
|
|
memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
|
|
|
|
obj_state = obj->funcs->atomic_duplicate_state(obj);
|
|
if (!obj_state)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
obj_state->obj = obj;
|
|
obj_state->changed = false;
|
|
|
|
kref_init(&obj_state->ref);
|
|
|
|
state->global_objs[index].state = obj_state;
|
|
state->global_objs[index].old_state =
|
|
intel_atomic_global_state_get(obj->state);
|
|
state->global_objs[index].new_state = obj_state;
|
|
state->global_objs[index].ptr = obj;
|
|
obj_state->state = state;
|
|
|
|
state->num_global_objs = num_objs;
|
|
|
|
drm_dbg_atomic(&i915->drm, "Added new global object %p state %p to %p\n",
|
|
obj, obj_state, state);
|
|
|
|
return obj_state;
|
|
}
|
|
|
|
struct intel_global_state *
|
|
intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
|
|
struct intel_global_obj *obj)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < state->num_global_objs; i++)
|
|
if (obj == state->global_objs[i].ptr)
|
|
return state->global_objs[i].old_state;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct intel_global_state *
|
|
intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
|
|
struct intel_global_obj *obj)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < state->num_global_objs; i++)
|
|
if (obj == state->global_objs[i].ptr)
|
|
return state->global_objs[i].new_state;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void intel_atomic_swap_global_state(struct intel_atomic_state *state)
|
|
{
|
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
struct intel_global_state *old_obj_state, *new_obj_state;
|
|
struct intel_global_obj *obj;
|
|
int i;
|
|
|
|
for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
|
|
new_obj_state, i) {
|
|
drm_WARN_ON(&dev_priv->drm, obj->state != old_obj_state);
|
|
|
|
/*
|
|
* If the new state wasn't modified (and properly
|
|
* locked for write access) we throw it away.
|
|
*/
|
|
if (!new_obj_state->changed)
|
|
continue;
|
|
|
|
assert_global_state_write_locked(dev_priv);
|
|
|
|
old_obj_state->state = state;
|
|
new_obj_state->state = NULL;
|
|
|
|
state->global_objs[i].state = old_obj_state;
|
|
|
|
intel_atomic_global_state_put(obj->state);
|
|
obj->state = intel_atomic_global_state_get(new_obj_state);
|
|
}
|
|
}
|
|
|
|
void intel_atomic_clear_global_state(struct intel_atomic_state *state)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < state->num_global_objs; i++) {
|
|
intel_atomic_global_state_put(state->global_objs[i].old_state);
|
|
intel_atomic_global_state_put(state->global_objs[i].new_state);
|
|
|
|
state->global_objs[i].ptr = NULL;
|
|
state->global_objs[i].state = NULL;
|
|
state->global_objs[i].old_state = NULL;
|
|
state->global_objs[i].new_state = NULL;
|
|
}
|
|
state->num_global_objs = 0;
|
|
}
|
|
|
|
int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
|
|
{
|
|
struct intel_atomic_state *state = obj_state->state;
|
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
struct intel_crtc *crtc;
|
|
|
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
|
int ret;
|
|
|
|
ret = drm_modeset_lock(&crtc->base.mutex,
|
|
state->base.acquire_ctx);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
obj_state->changed = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
|
|
{
|
|
struct intel_atomic_state *state = obj_state->state;
|
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
struct intel_crtc *crtc;
|
|
|
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
|
struct intel_crtc_state *crtc_state;
|
|
|
|
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
|
if (IS_ERR(crtc_state))
|
|
return PTR_ERR(crtc_state);
|
|
}
|
|
|
|
obj_state->changed = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
|
|
{
|
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
|
struct intel_crtc *crtc;
|
|
|
|
for_each_intel_crtc(&i915->drm, crtc)
|
|
if (!intel_atomic_get_new_crtc_state(state, crtc))
|
|
return false;
|
|
return true;
|
|
}
|