mirror of
https://github.com/torvalds/linux.git
synced 2026-04-25 18:12:26 -04:00
In order to reduce the DC5->DC2 restore time, wakelocks have been introduced in DMC so the driver can tell it when registers and other memory areas are going to be accessed and keep their respective blocks awake. Implement this in the driver by adding the concept of DMC wakelocks. When the driver needs to access memory which lies inside pre-defined ranges, it will tell DMC to set the wakelock, access the memory, then wait for a while and clear the wakelock. The wakelock state is protected in the driver with spinlocks to prevent concurrency issues. BSpec: 71583 Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Reviewed-by: Uma Shankar <uma.shankar@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240412094148.808179-2-luciano.coelho@intel.com Signed-off-by: Jani Nikula <jani.nikula@intel.com>
208 lines
4.5 KiB
C
208 lines
4.5 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
/*
|
|
* Copyright © 2019 Intel Corporation
|
|
*/
|
|
|
|
#ifndef __INTEL_DE_H__
|
|
#define __INTEL_DE_H__
|
|
|
|
#include "i915_drv.h"
|
|
#include "i915_trace.h"
|
|
#include "intel_uncore.h"
|
|
|
|
static inline u32
|
|
intel_de_read(struct drm_i915_private *i915, i915_reg_t reg)
|
|
{
|
|
u32 val;
|
|
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
val = intel_uncore_read(&i915->uncore, reg);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline u8
|
|
intel_de_read8(struct drm_i915_private *i915, i915_reg_t reg)
|
|
{
|
|
u8 val;
|
|
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
val = intel_uncore_read8(&i915->uncore, reg);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline u64
|
|
intel_de_read64_2x32(struct drm_i915_private *i915,
|
|
i915_reg_t lower_reg, i915_reg_t upper_reg)
|
|
{
|
|
u64 val;
|
|
|
|
intel_dmc_wl_get(i915, lower_reg);
|
|
intel_dmc_wl_get(i915, upper_reg);
|
|
|
|
val = intel_uncore_read64_2x32(&i915->uncore, lower_reg, upper_reg);
|
|
|
|
intel_dmc_wl_put(i915, upper_reg);
|
|
intel_dmc_wl_put(i915, lower_reg);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline void
|
|
intel_de_posting_read(struct drm_i915_private *i915, i915_reg_t reg)
|
|
{
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
intel_uncore_posting_read(&i915->uncore, reg);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
}
|
|
|
|
static inline void
|
|
intel_de_write(struct drm_i915_private *i915, i915_reg_t reg, u32 val)
|
|
{
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
intel_uncore_write(&i915->uncore, reg, val);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
}
|
|
|
|
static inline u32
|
|
__intel_de_rmw_nowl(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 clear, u32 set)
|
|
{
|
|
return intel_uncore_rmw(&i915->uncore, reg, clear, set);
|
|
}
|
|
|
|
static inline u32
|
|
intel_de_rmw(struct drm_i915_private *i915, i915_reg_t reg, u32 clear, u32 set)
|
|
{
|
|
u32 val;
|
|
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
val = __intel_de_rmw_nowl(i915, reg, clear, set);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline int
|
|
__intel_wait_for_register_nowl(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 mask, u32 value, unsigned int timeout)
|
|
{
|
|
return intel_wait_for_register(&i915->uncore, reg, mask,
|
|
value, timeout);
|
|
}
|
|
|
|
static inline int
|
|
intel_de_wait(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 mask, u32 value, unsigned int timeout)
|
|
{
|
|
int ret;
|
|
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
ret = __intel_wait_for_register_nowl(i915, reg, mask, value, timeout);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
intel_de_wait_fw(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 mask, u32 value, unsigned int timeout)
|
|
{
|
|
int ret;
|
|
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
ret = intel_wait_for_register_fw(&i915->uncore, reg, mask, value, timeout);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
intel_de_wait_custom(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 mask, u32 value,
|
|
unsigned int fast_timeout_us,
|
|
unsigned int slow_timeout_ms, u32 *out_value)
|
|
{
|
|
int ret;
|
|
|
|
intel_dmc_wl_get(i915, reg);
|
|
|
|
ret = __intel_wait_for_register(&i915->uncore, reg, mask, value,
|
|
fast_timeout_us, slow_timeout_ms, out_value);
|
|
|
|
intel_dmc_wl_put(i915, reg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
intel_de_wait_for_set(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 mask, unsigned int timeout)
|
|
{
|
|
return intel_de_wait(i915, reg, mask, mask, timeout);
|
|
}
|
|
|
|
static inline int
|
|
intel_de_wait_for_clear(struct drm_i915_private *i915, i915_reg_t reg,
|
|
u32 mask, unsigned int timeout)
|
|
{
|
|
return intel_de_wait(i915, reg, mask, 0, timeout);
|
|
}
|
|
|
|
/*
|
|
* Unlocked mmio-accessors, think carefully before using these.
|
|
*
|
|
* Certain architectures will die if the same cacheline is concurrently accessed
|
|
* by different clients (e.g. on Ivybridge). Access to registers should
|
|
* therefore generally be serialised, by either the dev_priv->uncore.lock or
|
|
* a more localised lock guarding all access to that bank of registers.
|
|
*/
|
|
static inline u32
|
|
intel_de_read_fw(struct drm_i915_private *i915, i915_reg_t reg)
|
|
{
|
|
u32 val;
|
|
|
|
val = intel_uncore_read_fw(&i915->uncore, reg);
|
|
trace_i915_reg_rw(false, reg, val, sizeof(val), true);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline void
|
|
intel_de_write_fw(struct drm_i915_private *i915, i915_reg_t reg, u32 val)
|
|
{
|
|
trace_i915_reg_rw(true, reg, val, sizeof(val), true);
|
|
intel_uncore_write_fw(&i915->uncore, reg, val);
|
|
}
|
|
|
|
static inline u32
|
|
intel_de_read_notrace(struct drm_i915_private *i915, i915_reg_t reg)
|
|
{
|
|
return intel_uncore_read_notrace(&i915->uncore, reg);
|
|
}
|
|
|
|
static inline void
|
|
intel_de_write_notrace(struct drm_i915_private *i915, i915_reg_t reg, u32 val)
|
|
{
|
|
intel_uncore_write_notrace(&i915->uncore, reg, val);
|
|
}
|
|
|
|
#endif /* __INTEL_DE_H__ */
|