Skip to content

Commit

Permalink
drm/msm/mdp5: provide dynamic bandwidth management
Browse files Browse the repository at this point in the history
This reverts commit e88bbc9.
  • Loading branch information
vldly authored and barni2000 committed Jul 25, 2024
1 parent 2067cf7 commit 586b089
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 37 deletions.
43 changes: 43 additions & 0 deletions drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ struct mdp5_crtc {
/* for unref'ing cursor bo's after scanout completes: */
struct drm_flip_work unref_cursor_work;

/* for lowering down the bandwidth after previous frame is complete */
struct drm_flip_work lower_bw_work;

struct mdp_irq vblank;
struct mdp_irq err;
struct mdp_irq pp_done;
Expand Down Expand Up @@ -173,11 +176,27 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val)
drm_gem_object_put(val);
}

static void lower_bw_worker(struct drm_flip_work *work, void *val)
{
struct mdp5_crtc *mdp5_crtc =
container_of(work, struct mdp5_crtc, lower_bw_work);
struct drm_crtc *crtc = &mdp5_crtc->base;
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base);

if (mdp5_cstate->old_crtc_bw > mdp5_cstate->new_crtc_bw) {
DBG("DOWN BW to %lld\n", mdp5_cstate->new_crtc_bw);
mdp5_kms_set_bandwidth(mdp5_kms);
mdp5_cstate->old_crtc_bw = mdp5_cstate->new_crtc_bw;
}
}

static void mdp5_crtc_flip_cleanup(struct drm_device *dev, void *ptr)
{
struct mdp5_crtc *mdp5_crtc = ptr;

drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work);
drm_flip_work_cleanup(&mdp5_crtc->lower_bw_work);
}

static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage)
Expand Down Expand Up @@ -707,6 +726,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
bool need_right_mixer = false;
int cnt = 0, i;
int ret;
u64 crtc_bw = 0;
enum mdp_mixer_stage_id start;

DBG("%s: check", crtc->name);
Expand All @@ -730,6 +750,9 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
*/
if (pstates[cnt].state->r_hwpipe)
need_right_mixer = true;

crtc_bw += pstates[cnt].state->plane_bw;

cnt++;

if (plane->type == DRM_PLANE_TYPE_CURSOR)
Expand All @@ -742,6 +765,10 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,

hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);

if (hw_cfg->perf.ab_inefficiency)
crtc_bw = mult_frac(crtc_bw, hw_cfg->perf.ab_inefficiency, 100);
mdp5_cstate->new_crtc_bw = crtc_bw;

/*
* we need a right hwmixer if the mode's width is greater than a single
* LM's max width
Expand Down Expand Up @@ -797,6 +824,7 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc,
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct drm_device *dev = crtc->dev;
unsigned long flags;

Expand All @@ -820,6 +848,12 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc,

blend_setup(crtc);

if (mdp5_cstate->old_crtc_bw < mdp5_cstate->new_crtc_bw) {
DBG("UP BW to %lld\n", mdp5_cstate->new_crtc_bw);
mdp5_kms_set_bandwidth(mdp5_kms);
mdp5_cstate->old_crtc_bw = mdp5_cstate->new_crtc_bw;
}

/* PP_DONE irq is only used by command mode for now.
* It is better to request pending before FLUSH and START trigger
* to make sure no pp_done irq missed.
Expand Down Expand Up @@ -1184,13 +1218,19 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
{
struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
struct drm_crtc *crtc = &mdp5_crtc->base;
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct msm_drm_private *priv = crtc->dev->dev_private;
unsigned pending;

mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);

pending = atomic_xchg(&mdp5_crtc->pending, 0);

if (mdp5_cstate->old_crtc_bw > mdp5_cstate->new_crtc_bw) {
drm_flip_work_queue(&mdp5_crtc->lower_bw_work, NULL);
drm_flip_work_commit(&mdp5_crtc->lower_bw_work, priv->wq);
}

if (pending & PENDING_FLIP) {
complete_flip(crtc, NULL);
}
Expand Down Expand Up @@ -1353,6 +1393,9 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
if (ret)
return ERR_PTR(ret);

drm_flip_work_init(&mdp5_crtc->lower_bw_work,
"lower bw", lower_bw_worker);

drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);

return crtc;
Expand Down
123 changes: 86 additions & 37 deletions drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include "msm_mmu.h"
#include "mdp5_kms.h"

#define MDP5_DEFAULT_BW MBps_to_icc(6400)
#define MDP5_CFG_BW MBps_to_icc(100)

static int mdp5_hw_init(struct msm_kms *kms)
{
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
Expand Down Expand Up @@ -229,6 +232,30 @@ static const struct mdp_kms_funcs kms_funcs = {
.set_irqmask = mdp5_set_irqmask,
};

void mdp5_kms_set_bandwidth(struct mdp5_kms *mdp5_kms)
{
int i;
u32 full_bw = 0;
struct drm_crtc *tmp_crtc;

if (!mdp5_kms->num_paths)
return;

drm_for_each_crtc(tmp_crtc, mdp5_kms->dev) {
if (!tmp_crtc->enabled)
continue;

full_bw += Bps_to_icc(to_mdp5_crtc_state(tmp_crtc->state)->new_crtc_bw);
}

full_bw /= mdp5_kms->num_paths;

DBG("SET BW to %d\n", full_bw);

for (i = 0; i < mdp5_kms->num_paths; i++)
icc_set_bw(mdp5_kms->paths[i], full_bw, full_bw);
}

static int mdp5_disable(struct mdp5_kms *mdp5_kms)
{
DBG("");
Expand All @@ -243,6 +270,14 @@ static int mdp5_disable(struct mdp5_kms *mdp5_kms)
clk_disable_unprepare(mdp5_kms->core_clk);
clk_disable_unprepare(mdp5_kms->lut_clk);

if (!mdp5_kms->enable_count) {
int i;

for (i = 0; i < mdp5_kms->num_paths; i++)
icc_set_bw(mdp5_kms->paths[i], 0, 0);
icc_set_bw(mdp5_kms->path_rot, 0, 0);
}

return 0;
}

Expand All @@ -252,6 +287,14 @@ static int mdp5_enable(struct mdp5_kms *mdp5_kms)

mdp5_kms->enable_count++;

if (mdp5_kms->enable_count == 1) {
int i;

for (i = 0; i < mdp5_kms->num_paths; i++)
icc_set_bw(mdp5_kms->paths[i], 0, MDP5_DEFAULT_BW);
icc_set_bw(mdp5_kms->path_rot, 0, MDP5_DEFAULT_BW);
}

clk_prepare_enable(mdp5_kms->ahb_clk);
clk_prepare_enable(mdp5_kms->axi_clk);
clk_prepare_enable(mdp5_kms->core_clk);
Expand Down Expand Up @@ -703,20 +746,63 @@ static int interface_init(struct mdp5_kms *mdp5_kms)
return 0;
}

static int mdp5_setup_interconnect(struct mdp5_kms *mdp5_kms)
{
struct icc_path *path0 = msm_icc_get(&mdp5_kms->pdev->dev, "mdp0-mem");
struct icc_path *path1 = msm_icc_get(&mdp5_kms->pdev->dev, "mdp1-mem");
struct icc_path *path_rot = msm_icc_get(&mdp5_kms->pdev->dev, "rotator-mem");

if (IS_ERR(path0))
return PTR_ERR(path0);

if (!path0) {
/* no interconnect support is not necessarily a fatal
* condition, the platform may simply not have an
* interconnect driver yet. But warn about it in case
* bootloader didn't setup bus clocks high enough for
* scanout.
*/
dev_warn(&mdp5_kms->pdev->dev, "No interconnect support may cause display underflows!\n");
return 0;
}

mdp5_kms->paths[0] = path0;
mdp5_kms->num_paths = 1;

if (!IS_ERR_OR_NULL(path1)) {
mdp5_kms->paths[1] = path1;
mdp5_kms->num_paths++;
}

if (!IS_ERR_OR_NULL(path_rot))
mdp5_kms->path_rot = path_rot;

return 0;
}

static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
struct mdp5_cfg *config;
u32 major, minor;
int ret;
int i;

mdp5_kms->dev = dev;

ret = mdp5_global_obj_init(mdp5_kms);
if (ret)
goto fail;

ret = mdp5_setup_interconnect(mdp5_kms);
if (ret)
goto fail;

for (i = 0; i < mdp5_kms->num_paths; i++)
icc_set_bw(mdp5_kms->paths[i], 0, MDP5_DEFAULT_BW);
icc_set_bw(mdp5_kms->path_rot, 0, MDP5_DEFAULT_BW);

/* we need to set a default rate before enabling. Set a safe
* rate first, then figure out hw revision, and then set a
* more optimal rate:
Expand Down Expand Up @@ -780,39 +866,6 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
return ret;
}

static int mdp5_setup_interconnect(struct platform_device *pdev)
{
struct icc_path *path0 = msm_icc_get(&pdev->dev, "mdp0-mem");
struct icc_path *path1 = msm_icc_get(&pdev->dev, "mdp1-mem");
struct icc_path *path_cfg = msm_icc_get(&pdev->dev, "cpu-cfg");
struct icc_path *path_rot = msm_icc_get(&pdev->dev, "rotator-mem");

if (IS_ERR(path0))
return PTR_ERR(path0);

if (!path0) {
/* no interconnect support is not necessarily a fatal
* condition, the platform may simply not have an
* interconnect driver yet. But warn about it in case
* bootloader didn't setup bus clocks high enough for
* scanout.
*/
dev_warn(&pdev->dev, "No interconnect support may cause display underflows!\n");
return 0;
}

icc_set_bw(path0, 0, MBps_to_icc(6400));

if (!IS_ERR_OR_NULL(path1))
icc_set_bw(path1, 0, MBps_to_icc(6400));
if (!IS_ERR_OR_NULL(path_rot))
icc_set_bw(path_rot, 0, MBps_to_icc(6400));
if (!IS_ERR_OR_NULL(path_cfg))
icc_set_bw(path_cfg, 0, MBps_to_icc(500));

return 0;
}

static int mdp5_dev_probe(struct platform_device *pdev)
{
struct mdp5_kms *mdp5_kms;
Expand All @@ -827,10 +880,6 @@ static int mdp5_dev_probe(struct platform_device *pdev)
if (!mdp5_kms)
return -ENOMEM;

ret = mdp5_setup_interconnect(pdev);
if (ret)
return ret;

mdp5_kms->pdev = pdev;

spin_lock_init(&mdp5_kms->resource_lock);
Expand Down
11 changes: 11 additions & 0 deletions drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "mdp5_ctl.h"
#include "mdp5_smp.h"

struct icc_path;
struct mdp5_kms {
struct mdp_kms base;

Expand Down Expand Up @@ -67,6 +68,10 @@ struct mdp5_kms {
struct mdp_irq error_handler;

int enable_count;

int num_paths;
struct icc_path *paths[2];
struct icc_path *path_rot;
};
#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)

Expand Down Expand Up @@ -104,6 +109,7 @@ struct mdp5_plane_state {
* display (ex. DSI command mode display)
*/
bool needs_dirtyfb;
u64 plane_bw;
};
#define to_mdp5_plane_state(x) \
container_of(x, struct mdp5_plane_state, base)
Expand Down Expand Up @@ -134,6 +140,9 @@ struct mdp5_crtc_state {
* writing CTL[n].START until encoder->enable()
*/
bool defer_start;

u64 new_crtc_bw;
u64 old_crtc_bw;
};
#define to_mdp5_crtc_state(x) \
container_of(x, struct mdp5_crtc_state, base)
Expand Down Expand Up @@ -294,6 +303,8 @@ void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode);
int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);

void mdp5_kms_set_bandwidth(struct mdp5_kms *mdp5_kms);

#ifdef CONFIG_DRM_MSM_DSI
void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
Expand Down
Loading

0 comments on commit 586b089

Please sign in to comment.