disp: msm: update topology based on clock requirement
Update the topology allocation by considering the required mode clock (vtotal x htotal x fps * fudge factor). Modes with a clock that exceeds the maximum SDE clock will be denoted as requiring a topology that uses two layer mixers. Change-Id: I3c773598b0d79cb6fea9d3a0e04d89ff84d67e13 Signed-off-by: Tatenda Chipeperekwa <tatendac@codeaurora.org>
This commit is contained in:
@@ -2060,6 +2060,7 @@ static enum drm_mode_status dp_display_validate_mode(
|
|||||||
struct dp_display_mode dp_mode;
|
struct dp_display_mode dp_mode;
|
||||||
bool dsc_en;
|
bool dsc_en;
|
||||||
u32 num_lm = 0;
|
u32 num_lm = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (!dp_display || !mode || !panel ||
|
if (!dp_display || !mode || !panel ||
|
||||||
!avail_res || !avail_res->max_mixer_width) {
|
!avail_res || !avail_res->max_mixer_width) {
|
||||||
@@ -2105,8 +2106,12 @@ static enum drm_mode_status dp_display_validate_mode(
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_lm = (avail_res->max_mixer_width <= mode->hdisplay) ?
|
rc = msm_get_mixer_count(dp->priv, mode, avail_res, &num_lm);
|
||||||
2 : 1;
|
if (rc) {
|
||||||
|
DP_ERR("error getting mixer count. rc:%d\n", rc);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
if (num_lm > avail_res->num_lm ||
|
if (num_lm > avail_res->num_lm ||
|
||||||
(num_lm == 2 && !avail_res->num_3dmux)) {
|
(num_lm == 2 && !avail_res->num_3dmux)) {
|
||||||
DP_MST_DEBUG("num_lm:%d, req lm:%d 3dmux:%d\n", num_lm,
|
DP_MST_DEBUG("num_lm:%d, req lm:%d 3dmux:%d\n", num_lm,
|
||||||
|
@@ -376,8 +376,6 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
|
|||||||
struct msm_mode_info *mode_info,
|
struct msm_mode_info *mode_info,
|
||||||
void *display, const struct msm_resource_caps_info *avail_res)
|
void *display, const struct msm_resource_caps_info *avail_res)
|
||||||
{
|
{
|
||||||
const u32 dual_lm = 2;
|
|
||||||
const u32 single_lm = 1;
|
|
||||||
const u32 single_intf = 1;
|
const u32 single_intf = 1;
|
||||||
const u32 no_enc = 0;
|
const u32 no_enc = 0;
|
||||||
struct msm_display_topology *topology;
|
struct msm_display_topology *topology;
|
||||||
@@ -385,9 +383,12 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
|
|||||||
struct dp_panel *dp_panel;
|
struct dp_panel *dp_panel;
|
||||||
struct dp_display_mode dp_mode;
|
struct dp_display_mode dp_mode;
|
||||||
struct dp_display *dp_disp = display;
|
struct dp_display *dp_disp = display;
|
||||||
|
struct msm_drm_private *priv;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (!drm_mode || !mode_info || !avail_res ||
|
if (!drm_mode || !mode_info || !avail_res ||
|
||||||
!avail_res->max_mixer_width || !connector || !display) {
|
!avail_res->max_mixer_width || !connector || !display ||
|
||||||
|
!connector->dev || !connector->dev->dev_private) {
|
||||||
DP_ERR("invalid params\n");
|
DP_ERR("invalid params\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -396,10 +397,17 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
|
|||||||
|
|
||||||
sde_conn = to_sde_connector(connector);
|
sde_conn = to_sde_connector(connector);
|
||||||
dp_panel = sde_conn->drv_panel;
|
dp_panel = sde_conn->drv_panel;
|
||||||
|
priv = connector->dev->dev_private;
|
||||||
|
|
||||||
topology = &mode_info->topology;
|
topology = &mode_info->topology;
|
||||||
topology->num_lm = (avail_res->max_mixer_width < drm_mode->hdisplay) ?
|
|
||||||
dual_lm : single_lm;
|
rc = msm_get_mixer_count(priv, drm_mode, avail_res,
|
||||||
|
&topology->num_lm);
|
||||||
|
if (rc) {
|
||||||
|
DP_ERR("error getting mixer count. rc:%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
topology->num_enc = no_enc;
|
topology->num_enc = no_enc;
|
||||||
topology->num_intf = single_intf;
|
topology->num_intf = single_intf;
|
||||||
|
|
||||||
|
@@ -1938,6 +1938,33 @@ msm_gem_smmu_address_space_get(struct drm_device *dev,
|
|||||||
return funcs->get_address_space(priv->kms, domain);
|
return funcs->get_address_space(priv->kms, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int msm_get_mixer_count(struct msm_drm_private *priv,
|
||||||
|
const struct drm_display_mode *mode,
|
||||||
|
const struct msm_resource_caps_info *res, u32 *num_lm)
|
||||||
|
{
|
||||||
|
struct msm_kms *kms;
|
||||||
|
const struct msm_kms_funcs *funcs;
|
||||||
|
|
||||||
|
if (!priv) {
|
||||||
|
DRM_ERROR("invalid drm private struct\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kms = priv->kms;
|
||||||
|
if (!kms) {
|
||||||
|
DRM_ERROR("invalid msm kms struct\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
funcs = kms->funcs;
|
||||||
|
if (!funcs || !funcs->get_mixer_count) {
|
||||||
|
DRM_ERROR("invalid function pointers\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return funcs->get_mixer_count(priv->kms, mode, res, num_lm);
|
||||||
|
}
|
||||||
|
|
||||||
static int msm_drm_bind(struct device *dev)
|
static int msm_drm_bind(struct device *dev)
|
||||||
{
|
{
|
||||||
return msm_drm_init(dev, &msm_driver);
|
return msm_drm_init(dev, &msm_driver);
|
||||||
|
@@ -1029,4 +1029,8 @@ static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)
|
|||||||
return remaining_jiffies;
|
return remaining_jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int msm_get_mixer_count(struct msm_drm_private *priv,
|
||||||
|
const struct drm_display_mode *mode,
|
||||||
|
const struct msm_resource_caps_info *res, u32 *num_lm);
|
||||||
|
|
||||||
#endif /* __MSM_DRV_H__ */
|
#endif /* __MSM_DRV_H__ */
|
||||||
|
@@ -122,6 +122,10 @@ struct msm_kms_funcs {
|
|||||||
int (*cont_splash_config)(struct msm_kms *kms);
|
int (*cont_splash_config)(struct msm_kms *kms);
|
||||||
/* check for continuous splash status */
|
/* check for continuous splash status */
|
||||||
bool (*check_for_splash)(struct msm_kms *kms);
|
bool (*check_for_splash)(struct msm_kms *kms);
|
||||||
|
/* topology information */
|
||||||
|
int (*get_mixer_count)(const struct msm_kms *kms,
|
||||||
|
const struct drm_display_mode *mode,
|
||||||
|
const struct msm_resource_caps_info *res, u32 *num_lm);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msm_kms {
|
struct msm_kms {
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
|
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
|
||||||
|
|
||||||
#include <drm/drm_crtc.h>
|
#include <drm/drm_crtc.h>
|
||||||
|
#include <drm/drm_fixed.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
@@ -2468,6 +2469,52 @@ static bool sde_kms_check_for_splash(struct msm_kms *kms)
|
|||||||
return sde_kms->splash_data.num_splash_displays;
|
return sde_kms->splash_data.num_splash_displays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sde_kms_get_mixer_count(const struct msm_kms *kms,
|
||||||
|
const struct drm_display_mode *mode,
|
||||||
|
const struct msm_resource_caps_info *res, u32 *num_lm)
|
||||||
|
{
|
||||||
|
struct sde_kms *sde_kms;
|
||||||
|
s64 mode_clock_hz = 0;
|
||||||
|
s64 max_mdp_clock_hz = 0;
|
||||||
|
s64 mdp_fudge_factor = 0;
|
||||||
|
s64 temp = 0;
|
||||||
|
s64 htotal_fp = 0;
|
||||||
|
s64 vtotal_fp = 0;
|
||||||
|
s64 vrefresh_fp = 0;
|
||||||
|
|
||||||
|
if (!num_lm) {
|
||||||
|
SDE_ERROR("invalid num_lm pointer\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*num_lm = 1;
|
||||||
|
if (!kms || !mode || !res) {
|
||||||
|
SDE_ERROR("invalid input args\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sde_kms = to_sde_kms(kms);
|
||||||
|
|
||||||
|
max_mdp_clock_hz = drm_fixp_from_fraction(
|
||||||
|
sde_kms->perf.max_core_clk_rate, 1);
|
||||||
|
mdp_fudge_factor = drm_fixp_from_fraction(105, 100); /* 1.05 */
|
||||||
|
htotal_fp = drm_fixp_from_fraction(mode->htotal, 1);
|
||||||
|
vtotal_fp = drm_fixp_from_fraction(mode->vtotal, 1);
|
||||||
|
vrefresh_fp = drm_fixp_from_fraction(mode->vrefresh, 1);
|
||||||
|
|
||||||
|
temp = drm_fixp_mul(htotal_fp, vtotal_fp);
|
||||||
|
temp = drm_fixp_mul(temp, vrefresh_fp);
|
||||||
|
mode_clock_hz = drm_fixp_mul(temp, mdp_fudge_factor);
|
||||||
|
if (mode_clock_hz > max_mdp_clock_hz ||
|
||||||
|
mode->hdisplay > res->max_mixer_width)
|
||||||
|
*num_lm = 2;
|
||||||
|
SDE_DEBUG("[%s] h=%d, v=%d, fps=%d, max_mdp_clk_hz=%llu, num_lm=%d\n",
|
||||||
|
mode->name, mode->htotal, mode->vtotal, mode->vrefresh,
|
||||||
|
sde_kms->perf.max_core_clk_rate, *num_lm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void _sde_kms_null_commit(struct drm_device *dev,
|
static void _sde_kms_null_commit(struct drm_device *dev,
|
||||||
struct drm_encoder *enc)
|
struct drm_encoder *enc)
|
||||||
{
|
{
|
||||||
@@ -2778,6 +2825,7 @@ static const struct msm_kms_funcs kms_funcs = {
|
|||||||
.get_address_space_device = _sde_kms_get_address_space_device,
|
.get_address_space_device = _sde_kms_get_address_space_device,
|
||||||
.postopen = _sde_kms_post_open,
|
.postopen = _sde_kms_post_open,
|
||||||
.check_for_splash = sde_kms_check_for_splash,
|
.check_for_splash = sde_kms_check_for_splash,
|
||||||
|
.get_mixer_count = sde_kms_get_mixer_count,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* the caller api needs to turn on clock before calling it */
|
/* the caller api needs to turn on clock before calling it */
|
||||||
|
Reference in New Issue
Block a user