Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7a5c833 authored by Ingrid Gallardo's avatar Ingrid Gallardo
Browse files

drm/msm/sde: add support for uidle feature



This change adds support to enable/disable microidle feature
in the sde kms driver. This feature allows the HW to increase
the DDR idle time by modifying the fetching patterns during
the active region of display frames.

Change-Id: I812297724ccf37ac65658957e468c0f72876a742
Signed-off-by: default avatarIngrid Gallardo <ingridg@codeaurora.org>
parent 3e63d02d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
	sde/sde_hw_reg_dma_v1_color_proc.o \
	sde/sde_hw_color_proc_v4.o \
	sde/sde_hw_ad4.o \
	sde/sde_hw_uidle.o \
	sde_edid_parser.o \
	sde_hdcp_1x.o \
	sde_hdcp_2x.o
+168 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "sde_kms.h"
#include "sde_trace.h"
#include "sde_crtc.h"
#include "sde_encoder.h"
#include "sde_core_perf.h"

#define SDE_PERF_MODE_STRING_SIZE	128
@@ -400,6 +401,173 @@ static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms,
			total_llcc_active ? true : false);
}

static void _sde_core_uidle_setup_wd(struct sde_kms *kms,
	bool enable)
{
	struct sde_uidle_wd_cfg wd;
	struct sde_hw_uidle *uidle;

	uidle = kms->hw_uidle;
	wd.enable = enable;
	wd.clear = false;
	wd.granularity = SDE_UIDLE_WD_GRANULARITY;
	wd.heart_beat = SDE_UIDLE_WD_HEART_BEAT;
	wd.load_value = SDE_UIDLE_WD_LOAD_VAL;

	if (uidle->ops.setup_wd_timer)
		uidle->ops.setup_wd_timer(uidle, &wd);
}

static void _sde_core_uidle_setup_cfg(struct sde_kms *kms,
	bool enable)
{
	struct sde_uidle_ctl_cfg cfg;
	struct sde_hw_uidle *uidle;

	uidle = kms->hw_uidle;
	cfg.uidle_enable = enable;
	cfg.fal10_danger =
		kms->catalog->uidle_cfg.fal10_danger;
	cfg.fal10_exit_cnt =
		kms->catalog->uidle_cfg.fal10_exit_cnt;
	cfg.fal10_exit_danger =
		kms->catalog->uidle_cfg.fal10_exit_danger;

	SDE_DEBUG("fal10_danger:%d fal10_exit_cnt:%d fal10_exit_danger:%d\n",
		cfg.fal10_danger, cfg.fal10_exit_cnt, cfg.fal10_exit_danger);
	SDE_EVT32(enable, cfg.fal10_danger, cfg.fal10_exit_cnt,
		cfg.fal10_exit_danger);

	if (uidle->ops.set_uidle_ctl)
		uidle->ops.set_uidle_ctl(uidle, &cfg);
}

static void _sde_core_uidle_setup_ctl(struct drm_crtc *crtc,
	bool enable)
{
	struct drm_encoder *drm_enc;

	/* Disable uidle in the CTL */
	drm_for_each_encoder(drm_enc, crtc->dev) {
		if (drm_enc->crtc != crtc)
			continue;

		sde_encoder_uidle_enable(drm_enc, enable);
	}
}

static int _sde_core_perf_enable_uidle(struct sde_kms *kms,
	struct drm_crtc *crtc, bool enable)
{
	int rc = 0;

	if (!kms->dev || !kms->dev->dev || !kms->hw_uidle) {
		SDE_ERROR("wrong params won't enable uidlen");
		rc = -EINVAL;
		goto exit;
	}

	/* if no status change, just return */
	if ((enable && kms->perf.uidle_enabled) ||
		(!enable && !kms->perf.uidle_enabled)) {
		SDE_DEBUG("no status change enable:%d uidle:%d\n",
			enable, kms->perf.uidle_enabled);
		goto exit;
	}

	SDE_EVT32(enable);
	_sde_core_uidle_setup_wd(kms, enable);
	_sde_core_uidle_setup_cfg(kms, enable);
	_sde_core_uidle_setup_ctl(crtc, enable);

	kms->perf.uidle_enabled = enable;

exit:
	return rc;
}

static inline bool _sde_core_perf_is_wb(struct drm_crtc *crtc)
{
	enum sde_intf_mode if_mode = INTF_MODE_NONE;

	if_mode = sde_crtc_get_intf_mode(crtc);
	if (if_mode == INTF_MODE_WB_BLOCK ||
		if_mode == INTF_MODE_WB_LINE)
		return true;

	return false;
}

static bool _sde_core_perf_is_cwb(struct drm_crtc *crtc)
{
	struct drm_encoder *encoder;

	/* if any other encoder is connected to same crtc in clone mode */
	drm_for_each_encoder(encoder, crtc->dev) {
		if (encoder->crtc == crtc &&
				sde_encoder_in_clone_mode(encoder)) {
			return true;
		}
	}

	return false;
}

void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc,
	bool enable)
{
	struct drm_crtc *tmp_crtc;
	struct sde_kms *kms;
	bool disable_uidle = false;
	u32 fps;

	if (!crtc) {
		SDE_ERROR("invalid crtc\n");
		return;
	}

	kms = _sde_crtc_get_kms(crtc);
	if (!kms || !kms->catalog) {
		SDE_ERROR("invalid kms\n");
		return;
	}

	mutex_lock(&sde_core_perf_lock);

	if (!kms->perf.catalog->uidle_cfg.uidle_rev ||
		!kms->perf.catalog->uidle_cfg.debugfs_ctrl) {
		SDE_DEBUG("uidle is not enabled %d %d\n",
			kms->perf.catalog->uidle_cfg.uidle_rev,
			kms->perf.catalog->uidle_cfg.debugfs_ctrl);
		goto exit;
	}

	drm_for_each_crtc(tmp_crtc, crtc->dev) {
		if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) {

			fps = sde_crtc_get_fps_mode(tmp_crtc);

			SDE_DEBUG("crtc=%d fps:%d wb:%d cwb:%d dis:%d en:%d\n",
				tmp_crtc->base.id, fps,
				_sde_core_perf_is_wb(tmp_crtc),
				_sde_core_perf_is_cwb(tmp_crtc),
				disable_uidle, enable);

			if (_sde_core_perf_is_wb(tmp_crtc) ||
				_sde_core_perf_is_cwb(tmp_crtc) || (!fps ||
				 fps > kms->perf.catalog->uidle_cfg.max_fps)) {
				disable_uidle = true;
				break;
			}
		}
	}

	_sde_core_perf_enable_uidle(kms, crtc,
		(enable && !disable_uidle) ? true : false);
exit:
	mutex_unlock(&sde_core_perf_lock);
}

static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
		struct drm_crtc *crtc, u32 bus_id)
{
+9 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct sde_core_perf_tune {
 * @sde_rsc_available: is display rsc available
 * @bw_vote_mode_updated: bandwidth vote mode update
 * @llcc_active: status of the llcc, true if active.
 * @uidle_enabled: indicates if uidle is already enabled
 */
struct sde_core_perf {
	struct drm_device *dev;
@@ -82,6 +83,7 @@ struct sde_core_perf {
	bool sde_rsc_available;
	bool bw_vote_mode_updated;
	bool llcc_active;
	bool uidle_enabled;
};

/**
@@ -108,6 +110,13 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc,
 */
void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc);

/**
 * sde_core_perf_crtc_update_uidle - attempts to enable uidle of the given crtc
 * @crtc: Pointer to crtc
 * @enable: enable/disable uidle
 */
void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable);

/**
 * sde_core_perf_destroy - destroy the given core performance context
 * @perf: Pointer to core performance context
+27 −1
Original line number Diff line number Diff line
@@ -2056,6 +2056,22 @@ enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
	return INTF_MODE_NONE;
}

u32 sde_crtc_get_fps_mode(struct drm_crtc *crtc)
{
	struct drm_encoder *encoder;

	if (!crtc || !crtc->dev) {
		SDE_ERROR("invalid crtc\n");
		return INTF_MODE_NONE;
	}

	drm_for_each_encoder(encoder, crtc->dev)
		if (encoder->crtc == crtc)
			return sde_encoder_get_fps(encoder);

	return 0;
}

static void sde_crtc_vblank_cb(void *data)
{
	struct drm_crtc *crtc = (struct drm_crtc *)data;
@@ -3751,6 +3767,9 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
	}
	sde_crtc->enabled = false;

	/* Try to disable uidle */
	sde_core_perf_crtc_update_uidle(crtc, false);

	if (atomic_read(&sde_crtc->frame_pending)) {
		SDE_ERROR("crtc%d frame_pending%d\n", crtc->base.id,
				atomic_read(&sde_crtc->frame_pending));
@@ -3861,7 +3880,14 @@ static void sde_crtc_enable(struct drm_crtc *crtc,
	SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
			sde_crtc->vblank_requested);

	/* return early if crtc is already enabled */
	/*
	 * Try to enable uidle (if possible), we do this before the call
	 * to return early during seamless dms mode, so any fps
	 * change is also consider to enable/disable UIDLE
	 */
	sde_core_perf_crtc_update_uidle(crtc, true);

	/* return early if crtc is already enabled, do this after UIDLE check */
	if (sde_crtc->enabled) {
		if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode))
			SDE_DEBUG("%s extra crtc enable expected during DMS\n",
+6 −0
Original line number Diff line number Diff line
@@ -511,6 +511,12 @@ int sde_crtc_register_custom_event(struct sde_kms *kms,
 */
enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc);

/**
 * sde_crtc_get_fps_mode - get frame rate of the given crtc
 * @crtc: Pointert to crtc
 */
u32 sde_crtc_get_fps_mode(struct drm_crtc *crtc);

/**
 * sde_crtc_get_client_type - check the crtc type- rt, nrt, rsc, etc.
 * @crtc: Pointer to crtc
Loading