mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
drm/i915/bw: Untangle dbuf bw from the sagv/mem bw stuff
Currently intel_bw.c contains basically three completely independent parts: - SAGV/memory bandwidth handling - DBuf bandwidth handling - "Maximum pipe read bandwidth" calculation, which is some kind of internal per-pipe bandwidth limit. Carve out the DBuf bandwdith handling into a separate file since there is no actual dependency between it and the rest of intel_bw.c. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20251013201236.30084-2-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola <mika.kahola@intel.com>
This commit is contained in:
@@ -242,6 +242,7 @@ i915-y += \
|
||||
display/intel_crtc.o \
|
||||
display/intel_crtc_state_dump.o \
|
||||
display/intel_cursor.o \
|
||||
display/intel_dbuf_bw.o \
|
||||
display/intel_display.o \
|
||||
display/intel_display_conversion.o \
|
||||
display/intel_display_driver.o \
|
||||
|
||||
@@ -3,16 +3,12 @@
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
|
||||
#include "soc/intel_dram.h"
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
#include "i915_utils.h"
|
||||
#include "intel_atomic.h"
|
||||
#include "intel_bw.h"
|
||||
#include "intel_cdclk.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_regs.h"
|
||||
@@ -22,14 +18,8 @@
|
||||
#include "intel_uncore.h"
|
||||
#include "skl_watermark.h"
|
||||
|
||||
struct intel_dbuf_bw {
|
||||
unsigned int max_bw[I915_MAX_DBUF_SLICES];
|
||||
u8 active_planes[I915_MAX_DBUF_SLICES];
|
||||
};
|
||||
|
||||
struct intel_bw_state {
|
||||
struct intel_global_state base;
|
||||
struct intel_dbuf_bw dbuf_bw[I915_MAX_PIPES];
|
||||
|
||||
/*
|
||||
* Contains a bit mask, used to determine, whether correspondent
|
||||
@@ -1264,184 +1254,6 @@ static int intel_bw_check_qgv_points(struct intel_display *display,
|
||||
old_bw_state, new_bw_state);
|
||||
}
|
||||
|
||||
static bool intel_dbuf_bw_changed(struct intel_display *display,
|
||||
const struct intel_dbuf_bw *old_dbuf_bw,
|
||||
const struct intel_dbuf_bw *new_dbuf_bw)
|
||||
{
|
||||
enum dbuf_slice slice;
|
||||
|
||||
for_each_dbuf_slice(display, slice) {
|
||||
if (old_dbuf_bw->max_bw[slice] != new_dbuf_bw->max_bw[slice] ||
|
||||
old_dbuf_bw->active_planes[slice] != new_dbuf_bw->active_planes[slice])
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool intel_bw_state_changed(struct intel_display *display,
|
||||
const struct intel_bw_state *old_bw_state,
|
||||
const struct intel_bw_state *new_bw_state)
|
||||
{
|
||||
enum pipe pipe;
|
||||
|
||||
for_each_pipe(display, pipe) {
|
||||
const struct intel_dbuf_bw *old_dbuf_bw =
|
||||
&old_bw_state->dbuf_bw[pipe];
|
||||
const struct intel_dbuf_bw *new_dbuf_bw =
|
||||
&new_bw_state->dbuf_bw[pipe];
|
||||
|
||||
if (intel_dbuf_bw_changed(display, old_dbuf_bw, new_dbuf_bw))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void skl_plane_calc_dbuf_bw(struct intel_dbuf_bw *dbuf_bw,
|
||||
struct intel_crtc *crtc,
|
||||
enum plane_id plane_id,
|
||||
const struct skl_ddb_entry *ddb,
|
||||
unsigned int data_rate)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(display, ddb);
|
||||
enum dbuf_slice slice;
|
||||
|
||||
/*
|
||||
* The arbiter can only really guarantee an
|
||||
* equal share of the total bw to each plane.
|
||||
*/
|
||||
for_each_dbuf_slice_in_mask(display, slice, dbuf_mask) {
|
||||
dbuf_bw->max_bw[slice] = max(dbuf_bw->max_bw[slice], data_rate);
|
||||
dbuf_bw->active_planes[slice] |= BIT(plane_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void skl_crtc_calc_dbuf_bw(struct intel_dbuf_bw *dbuf_bw,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
enum plane_id plane_id;
|
||||
|
||||
memset(dbuf_bw, 0, sizeof(*dbuf_bw));
|
||||
|
||||
if (!crtc_state->hw.active)
|
||||
return;
|
||||
|
||||
for_each_plane_id_on_crtc(crtc, plane_id) {
|
||||
/*
|
||||
* We assume cursors are small enough
|
||||
* to not cause bandwidth problems.
|
||||
*/
|
||||
if (plane_id == PLANE_CURSOR)
|
||||
continue;
|
||||
|
||||
skl_plane_calc_dbuf_bw(dbuf_bw, crtc, plane_id,
|
||||
&crtc_state->wm.skl.plane_ddb[plane_id],
|
||||
crtc_state->data_rate[plane_id]);
|
||||
|
||||
if (DISPLAY_VER(display) < 11)
|
||||
skl_plane_calc_dbuf_bw(dbuf_bw, crtc, plane_id,
|
||||
&crtc_state->wm.skl.plane_ddb_y[plane_id],
|
||||
crtc_state->data_rate[plane_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/* "Maximum Data Buffer Bandwidth" */
|
||||
static int
|
||||
intel_bw_dbuf_min_cdclk(struct intel_display *display,
|
||||
const struct intel_bw_state *bw_state)
|
||||
{
|
||||
unsigned int total_max_bw = 0;
|
||||
enum dbuf_slice slice;
|
||||
|
||||
for_each_dbuf_slice(display, slice) {
|
||||
int num_active_planes = 0;
|
||||
unsigned int max_bw = 0;
|
||||
enum pipe pipe;
|
||||
|
||||
/*
|
||||
* The arbiter can only really guarantee an
|
||||
* equal share of the total bw to each plane.
|
||||
*/
|
||||
for_each_pipe(display, pipe) {
|
||||
const struct intel_dbuf_bw *dbuf_bw = &bw_state->dbuf_bw[pipe];
|
||||
|
||||
max_bw = max(dbuf_bw->max_bw[slice], max_bw);
|
||||
num_active_planes += hweight8(dbuf_bw->active_planes[slice]);
|
||||
}
|
||||
max_bw *= num_active_planes;
|
||||
|
||||
total_max_bw = max(total_max_bw, max_bw);
|
||||
}
|
||||
|
||||
return DIV_ROUND_UP(total_max_bw, 64);
|
||||
}
|
||||
|
||||
int intel_bw_min_cdclk(struct intel_display *display,
|
||||
const struct intel_bw_state *bw_state)
|
||||
{
|
||||
int min_cdclk;
|
||||
|
||||
min_cdclk = intel_bw_dbuf_min_cdclk(display, bw_state);
|
||||
|
||||
return min_cdclk;
|
||||
}
|
||||
|
||||
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
|
||||
bool *need_cdclk_calc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct intel_bw_state *new_bw_state = NULL;
|
||||
const struct intel_bw_state *old_bw_state = NULL;
|
||||
const struct intel_crtc_state *old_crtc_state;
|
||||
const struct intel_crtc_state *new_crtc_state;
|
||||
struct intel_crtc *crtc;
|
||||
int ret, i;
|
||||
|
||||
if (DISPLAY_VER(display) < 9)
|
||||
return 0;
|
||||
|
||||
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
|
||||
new_crtc_state, i) {
|
||||
struct intel_dbuf_bw old_dbuf_bw, new_dbuf_bw;
|
||||
|
||||
skl_crtc_calc_dbuf_bw(&old_dbuf_bw, old_crtc_state);
|
||||
skl_crtc_calc_dbuf_bw(&new_dbuf_bw, new_crtc_state);
|
||||
|
||||
if (!intel_dbuf_bw_changed(display, &old_dbuf_bw, &new_dbuf_bw))
|
||||
continue;
|
||||
|
||||
new_bw_state = intel_atomic_get_bw_state(state);
|
||||
if (IS_ERR(new_bw_state))
|
||||
return PTR_ERR(new_bw_state);
|
||||
|
||||
old_bw_state = intel_atomic_get_old_bw_state(state);
|
||||
|
||||
new_bw_state->dbuf_bw[crtc->pipe] = new_dbuf_bw;
|
||||
}
|
||||
|
||||
if (!old_bw_state)
|
||||
return 0;
|
||||
|
||||
if (intel_bw_state_changed(display, old_bw_state, new_bw_state)) {
|
||||
int ret = intel_atomic_lock_global_state(&new_bw_state->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = intel_cdclk_update_bw_min_cdclk(state,
|
||||
intel_bw_min_cdclk(display, old_bw_state),
|
||||
intel_bw_min_cdclk(display, new_bw_state),
|
||||
need_cdclk_calc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_bw_check_data_rate(struct intel_atomic_state *state, bool *changed)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
@@ -1647,8 +1459,6 @@ void intel_bw_update_hw_state(struct intel_display *display)
|
||||
if (DISPLAY_VER(display) >= 11)
|
||||
intel_bw_crtc_update(bw_state, crtc_state);
|
||||
|
||||
skl_crtc_calc_dbuf_bw(&bw_state->dbuf_bw[pipe], crtc_state);
|
||||
|
||||
/* initially SAGV has been forced off */
|
||||
bw_state->pipe_sagv_reject |= BIT(pipe);
|
||||
}
|
||||
@@ -1666,7 +1476,6 @@ void intel_bw_crtc_disable_noatomic(struct intel_crtc *crtc)
|
||||
|
||||
bw_state->data_rate[pipe] = 0;
|
||||
bw_state->num_active_planes[pipe] = 0;
|
||||
memset(&bw_state->dbuf_bw[pipe], 0, sizeof(bw_state->dbuf_bw[pipe]));
|
||||
}
|
||||
|
||||
static struct intel_global_state *
|
||||
|
||||
@@ -30,10 +30,6 @@ void intel_bw_init_hw(struct intel_display *display);
|
||||
int intel_bw_init(struct intel_display *display);
|
||||
int intel_bw_atomic_check(struct intel_atomic_state *state);
|
||||
int intel_bw_crtc_min_cdclk(const struct intel_crtc_state *crtc_state);
|
||||
int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
|
||||
bool *need_cdclk_calc);
|
||||
int intel_bw_min_cdclk(struct intel_display *display,
|
||||
const struct intel_bw_state *bw_state);
|
||||
void intel_bw_update_hw_state(struct intel_display *display);
|
||||
void intel_bw_crtc_disable_noatomic(struct intel_crtc *crtc);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "intel_bw.h"
|
||||
#include "intel_cdclk.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_dbuf_bw.h"
|
||||
#include "intel_de.h"
|
||||
#include "intel_display_regs.h"
|
||||
#include "intel_display_types.h"
|
||||
@@ -133,8 +134,8 @@ struct intel_cdclk_state {
|
||||
*/
|
||||
struct intel_cdclk_config actual;
|
||||
|
||||
/* minimum acceptable cdclk to satisfy bandwidth requirements */
|
||||
int bw_min_cdclk;
|
||||
/* minimum acceptable cdclk to satisfy DBUF bandwidth requirements */
|
||||
int dbuf_bw_min_cdclk;
|
||||
/* minimum acceptable cdclk for each pipe */
|
||||
int min_cdclk[I915_MAX_PIPES];
|
||||
/* minimum acceptable voltage level for each pipe */
|
||||
@@ -2895,9 +2896,9 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
int old_min_cdclk, int new_min_cdclk,
|
||||
bool *need_cdclk_calc)
|
||||
int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
int old_min_cdclk, int new_min_cdclk,
|
||||
bool *need_cdclk_calc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct intel_cdclk_state *cdclk_state;
|
||||
@@ -2914,7 +2915,7 @@ int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
if (IS_ERR(cdclk_state))
|
||||
return PTR_ERR(cdclk_state);
|
||||
|
||||
old_min_cdclk = cdclk_state->bw_min_cdclk;
|
||||
old_min_cdclk = cdclk_state->dbuf_bw_min_cdclk;
|
||||
|
||||
if (new_min_cdclk == old_min_cdclk)
|
||||
return 0;
|
||||
@@ -2922,7 +2923,7 @@ int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
if (!allow_cdclk_decrease && new_min_cdclk < old_min_cdclk)
|
||||
return 0;
|
||||
|
||||
cdclk_state->bw_min_cdclk = new_min_cdclk;
|
||||
cdclk_state->dbuf_bw_min_cdclk = new_min_cdclk;
|
||||
|
||||
ret = intel_atomic_lock_global_state(&cdclk_state->base);
|
||||
if (ret)
|
||||
@@ -2931,7 +2932,7 @@ int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
*need_cdclk_calc = true;
|
||||
|
||||
drm_dbg_kms(display->drm,
|
||||
"bandwidth min cdclk: %d kHz -> %d kHz\n",
|
||||
"dbuf bandwidth min cdclk: %d kHz -> %d kHz\n",
|
||||
old_min_cdclk, new_min_cdclk);
|
||||
|
||||
return 0;
|
||||
@@ -2954,7 +2955,7 @@ static int intel_compute_min_cdclk(struct intel_atomic_state *state)
|
||||
int min_cdclk;
|
||||
|
||||
min_cdclk = cdclk_state->force_min_cdclk;
|
||||
min_cdclk = max(min_cdclk, cdclk_state->bw_min_cdclk);
|
||||
min_cdclk = max(min_cdclk, cdclk_state->dbuf_bw_min_cdclk);
|
||||
for_each_pipe(display, pipe)
|
||||
min_cdclk = max(min_cdclk, cdclk_state->min_cdclk[pipe]);
|
||||
|
||||
@@ -3480,7 +3481,7 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_bw_calc_min_cdclk(state, &need_cdclk_calc);
|
||||
ret = intel_dbuf_bw_calc_min_cdclk(state, &need_cdclk_calc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -3507,8 +3508,8 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state)
|
||||
|
||||
void intel_cdclk_update_hw_state(struct intel_display *display)
|
||||
{
|
||||
const struct intel_bw_state *bw_state =
|
||||
to_intel_bw_state(display->bw.obj.state);
|
||||
const struct intel_dbuf_bw_state *dbuf_bw_state =
|
||||
to_intel_dbuf_bw_state(display->dbuf_bw.obj.state);
|
||||
struct intel_cdclk_state *cdclk_state =
|
||||
to_intel_cdclk_state(display->cdclk.obj.state);
|
||||
struct intel_crtc *crtc;
|
||||
@@ -3530,7 +3531,7 @@ void intel_cdclk_update_hw_state(struct intel_display *display)
|
||||
cdclk_state->min_voltage_level[pipe] = crtc_state->min_voltage_level;
|
||||
}
|
||||
|
||||
cdclk_state->bw_min_cdclk = intel_bw_min_cdclk(display, bw_state);
|
||||
cdclk_state->dbuf_bw_min_cdclk = intel_dbuf_bw_min_cdclk(display, dbuf_bw_state);
|
||||
}
|
||||
|
||||
void intel_cdclk_crtc_disable_noatomic(struct intel_crtc *crtc)
|
||||
@@ -4024,11 +4025,6 @@ int intel_cdclk_min_cdclk(const struct intel_cdclk_state *cdclk_state, enum pipe
|
||||
return cdclk_state->min_cdclk[pipe];
|
||||
}
|
||||
|
||||
int intel_cdclk_bw_min_cdclk(const struct intel_cdclk_state *cdclk_state)
|
||||
{
|
||||
return cdclk_state->bw_min_cdclk;
|
||||
}
|
||||
|
||||
bool intel_cdclk_pmdemand_needs_update(struct intel_atomic_state *state)
|
||||
{
|
||||
const struct intel_cdclk_state *new_cdclk_state, *old_cdclk_state;
|
||||
|
||||
@@ -46,9 +46,9 @@ struct intel_cdclk_state *
|
||||
intel_atomic_get_cdclk_state(struct intel_atomic_state *state);
|
||||
void intel_cdclk_update_hw_state(struct intel_display *display);
|
||||
void intel_cdclk_crtc_disable_noatomic(struct intel_crtc *crtc);
|
||||
int intel_cdclk_update_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
int old_min_cdclk, int new_min_cdclk,
|
||||
bool *need_cdclk_calc);
|
||||
int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state,
|
||||
int old_min_cdclk, int new_min_cdclk,
|
||||
bool *need_cdclk_calc);
|
||||
|
||||
#define to_intel_cdclk_state(global_state) \
|
||||
container_of_const((global_state), struct intel_cdclk_state, base)
|
||||
@@ -65,7 +65,6 @@ int intel_cdclk_logical(const struct intel_cdclk_state *cdclk_state);
|
||||
int intel_cdclk_actual(const struct intel_cdclk_state *cdclk_state);
|
||||
int intel_cdclk_actual_voltage_level(const struct intel_cdclk_state *cdclk_state);
|
||||
int intel_cdclk_min_cdclk(const struct intel_cdclk_state *cdclk_state, enum pipe pipe);
|
||||
int intel_cdclk_bw_min_cdclk(const struct intel_cdclk_state *cdclk_state);
|
||||
bool intel_cdclk_pmdemand_needs_update(struct intel_atomic_state *state);
|
||||
void intel_cdclk_force_min_cdclk(struct intel_cdclk_state *cdclk_state, int force_min_cdclk);
|
||||
void intel_cdclk_read_hw(struct intel_display *display);
|
||||
|
||||
295
drivers/gpu/drm/i915/display/intel_dbuf_bw.c
Normal file
295
drivers/gpu/drm/i915/display/intel_dbuf_bw.c
Normal file
@@ -0,0 +1,295 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "intel_dbuf_bw.h"
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "skl_watermark.h"
|
||||
|
||||
struct intel_dbuf_bw {
|
||||
unsigned int max_bw[I915_MAX_DBUF_SLICES];
|
||||
u8 active_planes[I915_MAX_DBUF_SLICES];
|
||||
};
|
||||
|
||||
struct intel_dbuf_bw_state {
|
||||
struct intel_global_state base;
|
||||
struct intel_dbuf_bw dbuf_bw[I915_MAX_PIPES];
|
||||
};
|
||||
|
||||
struct intel_dbuf_bw_state *to_intel_dbuf_bw_state(struct intel_global_state *obj_state)
|
||||
{
|
||||
return container_of(obj_state, struct intel_dbuf_bw_state, base);
|
||||
}
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
intel_atomic_get_old_dbuf_bw_state(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct intel_global_state *dbuf_bw_state;
|
||||
|
||||
dbuf_bw_state = intel_atomic_get_old_global_obj_state(state, &display->dbuf_bw.obj);
|
||||
|
||||
return to_intel_dbuf_bw_state(dbuf_bw_state);
|
||||
}
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
intel_atomic_get_new_dbuf_bw_state(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct intel_global_state *dbuf_bw_state;
|
||||
|
||||
dbuf_bw_state = intel_atomic_get_new_global_obj_state(state, &display->dbuf_bw.obj);
|
||||
|
||||
return to_intel_dbuf_bw_state(dbuf_bw_state);
|
||||
}
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
intel_atomic_get_dbuf_bw_state(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct intel_global_state *dbuf_bw_state;
|
||||
|
||||
dbuf_bw_state = intel_atomic_get_global_obj_state(state, &display->dbuf_bw.obj);
|
||||
if (IS_ERR(dbuf_bw_state))
|
||||
return ERR_CAST(dbuf_bw_state);
|
||||
|
||||
return to_intel_dbuf_bw_state(dbuf_bw_state);
|
||||
}
|
||||
|
||||
static bool intel_dbuf_bw_changed(struct intel_display *display,
|
||||
const struct intel_dbuf_bw *old_dbuf_bw,
|
||||
const struct intel_dbuf_bw *new_dbuf_bw)
|
||||
{
|
||||
enum dbuf_slice slice;
|
||||
|
||||
for_each_dbuf_slice(display, slice) {
|
||||
if (old_dbuf_bw->max_bw[slice] != new_dbuf_bw->max_bw[slice] ||
|
||||
old_dbuf_bw->active_planes[slice] != new_dbuf_bw->active_planes[slice])
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool intel_dbuf_bw_state_changed(struct intel_display *display,
|
||||
const struct intel_dbuf_bw_state *old_dbuf_bw_state,
|
||||
const struct intel_dbuf_bw_state *new_dbuf_bw_state)
|
||||
{
|
||||
enum pipe pipe;
|
||||
|
||||
for_each_pipe(display, pipe) {
|
||||
const struct intel_dbuf_bw *old_dbuf_bw =
|
||||
&old_dbuf_bw_state->dbuf_bw[pipe];
|
||||
const struct intel_dbuf_bw *new_dbuf_bw =
|
||||
&new_dbuf_bw_state->dbuf_bw[pipe];
|
||||
|
||||
if (intel_dbuf_bw_changed(display, old_dbuf_bw, new_dbuf_bw))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void skl_plane_calc_dbuf_bw(struct intel_dbuf_bw *dbuf_bw,
|
||||
struct intel_crtc *crtc,
|
||||
enum plane_id plane_id,
|
||||
const struct skl_ddb_entry *ddb,
|
||||
unsigned int data_rate)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(display, ddb);
|
||||
enum dbuf_slice slice;
|
||||
|
||||
/*
|
||||
* The arbiter can only really guarantee an
|
||||
* equal share of the total bw to each plane.
|
||||
*/
|
||||
for_each_dbuf_slice_in_mask(display, slice, dbuf_mask) {
|
||||
dbuf_bw->max_bw[slice] = max(dbuf_bw->max_bw[slice], data_rate);
|
||||
dbuf_bw->active_planes[slice] |= BIT(plane_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void skl_crtc_calc_dbuf_bw(struct intel_dbuf_bw *dbuf_bw,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc_state);
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
enum plane_id plane_id;
|
||||
|
||||
memset(dbuf_bw, 0, sizeof(*dbuf_bw));
|
||||
|
||||
if (!crtc_state->hw.active)
|
||||
return;
|
||||
|
||||
for_each_plane_id_on_crtc(crtc, plane_id) {
|
||||
/*
|
||||
* We assume cursors are small enough
|
||||
* to not cause bandwidth problems.
|
||||
*/
|
||||
if (plane_id == PLANE_CURSOR)
|
||||
continue;
|
||||
|
||||
skl_plane_calc_dbuf_bw(dbuf_bw, crtc, plane_id,
|
||||
&crtc_state->wm.skl.plane_ddb[plane_id],
|
||||
crtc_state->data_rate[plane_id]);
|
||||
|
||||
if (DISPLAY_VER(display) < 11)
|
||||
skl_plane_calc_dbuf_bw(dbuf_bw, crtc, plane_id,
|
||||
&crtc_state->wm.skl.plane_ddb_y[plane_id],
|
||||
crtc_state->data_rate[plane_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/* "Maximum Data Buffer Bandwidth" */
|
||||
int intel_dbuf_bw_min_cdclk(struct intel_display *display,
|
||||
const struct intel_dbuf_bw_state *dbuf_bw_state)
|
||||
{
|
||||
unsigned int total_max_bw = 0;
|
||||
enum dbuf_slice slice;
|
||||
|
||||
for_each_dbuf_slice(display, slice) {
|
||||
int num_active_planes = 0;
|
||||
unsigned int max_bw = 0;
|
||||
enum pipe pipe;
|
||||
|
||||
/*
|
||||
* The arbiter can only really guarantee an
|
||||
* equal share of the total bw to each plane.
|
||||
*/
|
||||
for_each_pipe(display, pipe) {
|
||||
const struct intel_dbuf_bw *dbuf_bw = &dbuf_bw_state->dbuf_bw[pipe];
|
||||
|
||||
max_bw = max(dbuf_bw->max_bw[slice], max_bw);
|
||||
num_active_planes += hweight8(dbuf_bw->active_planes[slice]);
|
||||
}
|
||||
max_bw *= num_active_planes;
|
||||
|
||||
total_max_bw = max(total_max_bw, max_bw);
|
||||
}
|
||||
|
||||
return DIV_ROUND_UP(total_max_bw, 64);
|
||||
}
|
||||
|
||||
int intel_dbuf_bw_calc_min_cdclk(struct intel_atomic_state *state,
|
||||
bool *need_cdclk_calc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(state);
|
||||
struct intel_dbuf_bw_state *new_dbuf_bw_state = NULL;
|
||||
const struct intel_dbuf_bw_state *old_dbuf_bw_state = NULL;
|
||||
const struct intel_crtc_state *old_crtc_state;
|
||||
const struct intel_crtc_state *new_crtc_state;
|
||||
struct intel_crtc *crtc;
|
||||
int ret, i;
|
||||
|
||||
if (DISPLAY_VER(display) < 9)
|
||||
return 0;
|
||||
|
||||
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
|
||||
new_crtc_state, i) {
|
||||
struct intel_dbuf_bw old_dbuf_bw, new_dbuf_bw;
|
||||
|
||||
skl_crtc_calc_dbuf_bw(&old_dbuf_bw, old_crtc_state);
|
||||
skl_crtc_calc_dbuf_bw(&new_dbuf_bw, new_crtc_state);
|
||||
|
||||
if (!intel_dbuf_bw_changed(display, &old_dbuf_bw, &new_dbuf_bw))
|
||||
continue;
|
||||
|
||||
new_dbuf_bw_state = intel_atomic_get_dbuf_bw_state(state);
|
||||
if (IS_ERR(new_dbuf_bw_state))
|
||||
return PTR_ERR(new_dbuf_bw_state);
|
||||
|
||||
old_dbuf_bw_state = intel_atomic_get_old_dbuf_bw_state(state);
|
||||
|
||||
new_dbuf_bw_state->dbuf_bw[crtc->pipe] = new_dbuf_bw;
|
||||
}
|
||||
|
||||
if (!old_dbuf_bw_state)
|
||||
return 0;
|
||||
|
||||
if (intel_dbuf_bw_state_changed(display, old_dbuf_bw_state, new_dbuf_bw_state)) {
|
||||
ret = intel_atomic_lock_global_state(&new_dbuf_bw_state->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = intel_cdclk_update_dbuf_bw_min_cdclk(state,
|
||||
intel_dbuf_bw_min_cdclk(display, old_dbuf_bw_state),
|
||||
intel_dbuf_bw_min_cdclk(display, new_dbuf_bw_state),
|
||||
need_cdclk_calc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_dbuf_bw_update_hw_state(struct intel_display *display)
|
||||
{
|
||||
struct intel_dbuf_bw_state *dbuf_bw_state =
|
||||
to_intel_dbuf_bw_state(display->dbuf_bw.obj.state);
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
if (DISPLAY_VER(display) < 9)
|
||||
return;
|
||||
|
||||
for_each_intel_crtc(display->drm, crtc) {
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
to_intel_crtc_state(crtc->base.state);
|
||||
|
||||
skl_crtc_calc_dbuf_bw(&dbuf_bw_state->dbuf_bw[crtc->pipe], crtc_state);
|
||||
}
|
||||
}
|
||||
|
||||
void intel_dbuf_bw_crtc_disable_noatomic(struct intel_crtc *crtc)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(crtc);
|
||||
struct intel_dbuf_bw_state *dbuf_bw_state =
|
||||
to_intel_dbuf_bw_state(display->dbuf_bw.obj.state);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
if (DISPLAY_VER(display) < 9)
|
||||
return;
|
||||
|
||||
memset(&dbuf_bw_state->dbuf_bw[pipe], 0, sizeof(dbuf_bw_state->dbuf_bw[pipe]));
|
||||
}
|
||||
|
||||
static struct intel_global_state *
|
||||
intel_dbuf_bw_duplicate_state(struct intel_global_obj *obj)
|
||||
{
|
||||
struct intel_dbuf_bw_state *state;
|
||||
|
||||
state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
return &state->base;
|
||||
}
|
||||
|
||||
static void intel_dbuf_bw_destroy_state(struct intel_global_obj *obj,
|
||||
struct intel_global_state *state)
|
||||
{
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static const struct intel_global_state_funcs intel_dbuf_bw_funcs = {
|
||||
.atomic_duplicate_state = intel_dbuf_bw_duplicate_state,
|
||||
.atomic_destroy_state = intel_dbuf_bw_destroy_state,
|
||||
};
|
||||
|
||||
int intel_dbuf_bw_init(struct intel_display *display)
|
||||
{
|
||||
struct intel_dbuf_bw_state *state;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
intel_atomic_global_obj_init(display, &display->dbuf_bw.obj,
|
||||
&state->base, &intel_dbuf_bw_funcs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
37
drivers/gpu/drm/i915/display/intel_dbuf_bw.h
Normal file
37
drivers/gpu/drm/i915/display/intel_dbuf_bw.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __INTEL_DBUF_BW_H__
|
||||
#define __INTEL_DBUF_BW_H__
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
|
||||
struct intel_atomic_state;
|
||||
struct intel_dbuf_bw_state;
|
||||
struct intel_crtc;
|
||||
struct intel_display;
|
||||
struct intel_global_state;
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
to_intel_dbuf_bw_state(struct intel_global_state *obj_state);
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
intel_atomic_get_old_dbuf_bw_state(struct intel_atomic_state *state);
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
intel_atomic_get_new_dbuf_bw_state(struct intel_atomic_state *state);
|
||||
|
||||
struct intel_dbuf_bw_state *
|
||||
intel_atomic_get_dbuf_bw_state(struct intel_atomic_state *state);
|
||||
|
||||
int intel_dbuf_bw_init(struct intel_display *display);
|
||||
int intel_dbuf_bw_calc_min_cdclk(struct intel_atomic_state *state,
|
||||
bool *need_cdclk_calc);
|
||||
int intel_dbuf_bw_min_cdclk(struct intel_display *display,
|
||||
const struct intel_dbuf_bw_state *dbuf_bw_state);
|
||||
void intel_dbuf_bw_update_hw_state(struct intel_display *display);
|
||||
void intel_dbuf_bw_crtc_disable_noatomic(struct intel_crtc *crtc);
|
||||
|
||||
#endif /* __INTEL_DBUF_BW_H__ */
|
||||
@@ -369,6 +369,10 @@ struct intel_display {
|
||||
struct intel_global_obj obj;
|
||||
} dbuf;
|
||||
|
||||
struct {
|
||||
struct intel_global_obj obj;
|
||||
} dbuf_bw;
|
||||
|
||||
struct {
|
||||
/*
|
||||
* dkl.phy_lock protects against concurrent access of the
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "intel_cdclk.h"
|
||||
#include "intel_color.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_dbuf_bw.h"
|
||||
#include "intel_display_core.h"
|
||||
#include "intel_display_debugfs.h"
|
||||
#include "intel_display_driver.h"
|
||||
@@ -285,6 +286,10 @@ int intel_display_driver_probe_noirq(struct intel_display *display)
|
||||
if (ret)
|
||||
goto cleanup_wq_unordered;
|
||||
|
||||
ret = intel_dbuf_bw_init(display);
|
||||
if (ret)
|
||||
goto cleanup_wq_unordered;
|
||||
|
||||
ret = intel_bw_init(display);
|
||||
if (ret)
|
||||
goto cleanup_wq_unordered;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "intel_color.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_crtc_state_dump.h"
|
||||
#include "intel_dbuf_bw.h"
|
||||
#include "intel_ddi.h"
|
||||
#include "intel_de.h"
|
||||
#include "intel_display.h"
|
||||
@@ -176,6 +177,7 @@ static void intel_crtc_disable_noatomic_complete(struct intel_crtc *crtc)
|
||||
intel_cdclk_crtc_disable_noatomic(crtc);
|
||||
skl_wm_crtc_disable_noatomic(crtc);
|
||||
intel_bw_crtc_disable_noatomic(crtc);
|
||||
intel_dbuf_bw_crtc_disable_noatomic(crtc);
|
||||
|
||||
intel_pmdemand_update_port_clock(display, pmdemand_state, pipe, 0);
|
||||
}
|
||||
@@ -872,6 +874,7 @@ static void intel_modeset_readout_hw_state(struct intel_display *display)
|
||||
intel_wm_get_hw_state(display);
|
||||
|
||||
intel_bw_update_hw_state(display);
|
||||
intel_dbuf_bw_update_hw_state(display);
|
||||
intel_cdclk_update_hw_state(display);
|
||||
|
||||
intel_pmdemand_init_pmdemand_params(display, pmdemand_state);
|
||||
|
||||
@@ -240,6 +240,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
|
||||
i915-display/intel_crtc_state_dump.o \
|
||||
i915-display/intel_cursor.o \
|
||||
i915-display/intel_cx0_phy.o \
|
||||
i915-display/intel_dbuf_bw.o \
|
||||
i915-display/intel_ddi.o \
|
||||
i915-display/intel_ddi_buf_trans.o \
|
||||
i915-display/intel_display.o \
|
||||
|
||||
Reference in New Issue
Block a user