summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-05-09 05:09:47 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2018-05-09 05:09:47 -0700
commitd71805810933f9ebbd2eb83e80e560c40d526ece (patch)
treede0295fb6bfbf419fa881e13519925e99056bd66 /drivers/gpu
parent43fb4adbdcdb9c312cb53fdc93ee8fd81569b96d (diff)
parentc96659a88a12f1363d2cebbc9bd73eb3cafda1ea (diff)
Merge "drm: msm: improve early splash mechanism"
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c13
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c21
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.c100
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.h29
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c5
-rw-r--r--drivers/gpu/drm/msm/sde/sde_rm.c248
-rw-r--r--drivers/gpu/drm/msm/sde/sde_rm.h12
-rw-r--r--drivers/gpu/drm/msm/sde/sde_splash.c212
-rw-r--r--drivers/gpu/drm/msm/sde/sde_splash.h47
9 files changed, 517 insertions, 170 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index e8dfd1f08236..f74a682c5f04 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -572,8 +572,6 @@ void sde_connector_complete_commit(struct drm_connector *connector)
{
struct drm_device *dev;
struct msm_drm_private *priv;
- struct sde_connector *c_conn;
- struct sde_kms *sde_kms;
if (!connector) {
SDE_ERROR("invalid connector\n");
@@ -582,7 +580,6 @@ void sde_connector_complete_commit(struct drm_connector *connector)
dev = connector->dev;
priv = dev->dev_private;
- sde_kms = to_sde_kms(priv->kms);
/* signal connector's retire fence */
sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
@@ -590,14 +587,8 @@ void sde_connector_complete_commit(struct drm_connector *connector)
/* after first vsync comes,
* early splash resource should start to be released.
*/
- if (sde_splash_get_lk_complete_status(&sde_kms->splash_info)) {
- c_conn = to_sde_connector(connector);
-
- sde_splash_clean_up_free_resource(priv->kms,
- &priv->phandle,
- c_conn->connector_type,
- c_conn->display);
- }
+ if (sde_splash_get_lk_complete_status(priv->kms))
+ sde_splash_free_resource(priv->kms, &priv->phandle);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index cd00ab4b4a81..6ad1ce16c20a 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -304,6 +304,8 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
struct sde_crtc_mixer *mixer = sde_crtc->mixers;
struct sde_hw_ctl *ctl;
struct sde_hw_mixer *lm;
+ struct sde_splash_info *sinfo;
+ struct sde_kms *sde_kms = _sde_crtc_get_kms(crtc);
int i;
@@ -314,6 +316,17 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
return;
}
+ if (!sde_kms) {
+ SDE_ERROR("invalid sde_kms\n");
+ return;
+ }
+
+ sinfo = &sde_kms->splash_info;
+ if (!sinfo) {
+ SDE_ERROR("invalid splash info\n");
+ return;
+ }
+
for (i = 0; i < sde_crtc->num_mixers; i++) {
if (!mixer[i].hw_lm || !mixer[i].hw_ctl) {
SDE_ERROR("invalid lm or ctl assigned to mixer\n");
@@ -323,7 +336,10 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
mixer[i].flush_mask = 0;
if (mixer[i].hw_ctl->ops.clear_all_blendstages)
mixer[i].hw_ctl->ops.clear_all_blendstages(
- mixer[i].hw_ctl);
+ mixer[i].hw_ctl,
+ sinfo->handoff,
+ sinfo->reserved_pipe_info,
+ MAX_BLOCKS);
}
/* initialize stage cfg */
@@ -350,7 +366,8 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
mixer[i].flush_mask);
ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
- &sde_crtc->stage_cfg, i);
+ &sde_crtc->stage_cfg, i,
+ sinfo->handoff, sinfo->reserved_pipe_info, MAX_BLOCKS);
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 46e2a13cecc4..341738f624db 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -258,6 +258,35 @@ static inline int sde_hw_ctl_get_bitmask_cdm(struct sde_hw_ctl *ctx,
return 0;
}
+static inline int sde_hw_ctl_get_splash_mixercfg(const u32 *resv_pipes,
+ u32 length)
+{
+ int i = 0;
+ u32 mixercfg = 0;
+
+ for (i = 0; i < length; i++) {
+ /* LK's splash VIG layer always stays on top */
+ switch (resv_pipes[i]) {
+ case SSPP_VIG0:
+ mixercfg |= 0x7 << 0;
+ break;
+ case SSPP_VIG1:
+ mixercfg |= 0x7 << 3;
+ break;
+ case SSPP_VIG2:
+ mixercfg |= 0x7 << 6;
+ break;
+ case SSPP_VIG3:
+ mixercfg |= 0x7 << 26;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return mixercfg;
+}
+
static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 count)
{
struct sde_hw_blk_reg_map *c = &ctx->hw;
@@ -312,15 +341,29 @@ static int sde_hw_ctl_wait_reset_status(struct sde_hw_ctl *ctx)
return 0;
}
-static void sde_hw_ctl_clear_all_blendstages(struct sde_hw_ctl *ctx)
+static void sde_hw_ctl_clear_all_blendstages(struct sde_hw_ctl *ctx,
+ bool handoff, const u32 *resv_pipes, u32 resv_pipes_length)
{
struct sde_hw_blk_reg_map *c = &ctx->hw;
int i;
for (i = 0; i < ctx->mixer_count; i++) {
int mixer_id = ctx->mixer_hw_caps[i].id;
+ u32 mixercfg = 0;
+
+ /*
+ * if bootloaer still has early RVC running, mixer status
+ * can't be direcly cleared.
+ */
+ if (handoff) {
+ mixercfg =
+ sde_hw_ctl_get_splash_mixercfg(resv_pipes,
+ resv_pipes_length);
+
+ mixercfg &= SDE_REG_READ(c, CTL_LAYER(mixer_id));
+ }
- SDE_REG_WRITE(c, CTL_LAYER(mixer_id), 0);
+ SDE_REG_WRITE(c, CTL_LAYER(mixer_id), mixercfg);
SDE_REG_WRITE(c, CTL_LAYER_EXT(mixer_id), 0);
SDE_REG_WRITE(c, CTL_LAYER_EXT2(mixer_id), 0);
SDE_REG_WRITE(c, CTL_LAYER_EXT3(mixer_id), 0);
@@ -328,7 +371,8 @@ static void sde_hw_ctl_clear_all_blendstages(struct sde_hw_ctl *ctx)
}
static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx,
- enum sde_lm lm, struct sde_hw_stage_cfg *stage_cfg, u32 index)
+ enum sde_lm lm, struct sde_hw_stage_cfg *stage_cfg, u32 index,
+ bool handoff, const u32 *resv_pipes, u32 resv_pipes_length)
{
struct sde_hw_blk_reg_map *c = &ctx->hw;
u32 mixercfg, mixercfg_ext, mix, ext, mixercfg_ext2;
@@ -353,6 +397,20 @@ static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx,
mixercfg_ext = 0;
mixercfg_ext2 = 0;
+ /*
+ * if bootloader still have RVC running, its mixer stauts
+ * should be updated to kernel's mixer setup.
+ */
+ if (handoff) {
+ mixercfg =
+ sde_hw_ctl_get_splash_mixercfg(resv_pipes,
+ resv_pipes_length);
+
+ mixercfg &= SDE_REG_READ(c, CTL_LAYER(lm));
+ mixercfg |= BIT(24);
+ stages--;
+ }
+
for (i = 0; i <= stages; i++) {
/* overflow to ext register if 'i + 1 > 7' */
mix = (i + 1) & 0x7;
@@ -458,6 +516,38 @@ static void sde_hw_ctl_intf_cfg(struct sde_hw_ctl *ctx,
SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
}
+static inline u32 sde_hw_ctl_read_ctl_top_for_splash(struct sde_hw_ctl *ctx)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 ctl_top;
+
+ if (!ctx) {
+ pr_err("Invalid ctx\n");
+ return 0;
+ }
+
+ c = &ctx->hw;
+ ctl_top = SDE_REG_READ(c, CTL_TOP);
+ return ctl_top;
+}
+
+static inline u32 sde_hw_ctl_read_ctl_layers_for_splash(struct sde_hw_ctl *ctx,
+ int index)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 ctl_top;
+
+ if (!ctx) {
+ pr_err("Invalid ctx\n");
+ return 0;
+ }
+
+ c = &ctx->hw;
+ ctl_top = SDE_REG_READ(c, CTL_LAYER(index));
+
+ return ctl_top;
+}
+
static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
unsigned long cap)
{
@@ -478,6 +568,8 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf;
ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm;
ops->get_bitmask_wb = sde_hw_ctl_get_bitmask_wb;
+ ops->read_ctl_top_for_splash = sde_hw_ctl_read_ctl_top_for_splash;
+ ops->read_ctl_layers_for_splash = sde_hw_ctl_read_ctl_layers_for_splash;
};
struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 74dbde92639a..a008ecf4a11d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -146,17 +146,40 @@ struct sde_hw_ctl_ops {
/**
* Set all blend stages to disabled
* @ctx : ctl path ctx pointer
+ * @handoff : handoff flag
+ * @resv_pipes : reserved pipes in DT
+ * @resv_pipes_length: array size of array reserved_pipes
*/
- void (*clear_all_blendstages)(struct sde_hw_ctl *ctx);
+ void (*clear_all_blendstages)(struct sde_hw_ctl *ctx,
+ bool handoff, const u32 *resv_pipes, u32 resv_pipes_length);
/**
* Configure layer mixer to pipe configuration
* @ctx : ctl path ctx pointer
* @lm : layer mixer enumeration
* @cfg : blend stage configuration
+ * @handoff : handoff flag
+ * @resv_pipes : reserved pipes in DT
+ * @resv_pipes_length: array size of array reserved_pipes
*/
void (*setup_blendstage)(struct sde_hw_ctl *ctx,
- enum sde_lm lm, struct sde_hw_stage_cfg *cfg, u32 index);
+ enum sde_lm lm, struct sde_hw_stage_cfg *cfg, u32 index,
+ bool handoff, const u32 *resv_pipes, u32 resv_pipes_length);
+
+ /**
+ * read CTL_TOP register value for splash case
+ * @ctx : ctl path ctx pointer
+ * @Return : CTL top register value
+ */
+ u32 (*read_ctl_top_for_splash)(struct sde_hw_ctl *ctx);
+
+ /**
+ * read CTL layers register value for splash case
+ * @ctx : ctl path ctx pointer
+ * @index : layer index for this ctl path
+ * @Return : CTL layers register value
+ */
+ u32 (*read_ctl_layers_for_splash)(struct sde_hw_ctl *ctx, int index);
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index b95157b28855..1da8b5b4ff10 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -343,8 +343,9 @@ static void sde_kms_prepare_commit(struct msm_kms *kms,
struct drm_device *dev = sde_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
- if (sde_kms->splash_info.handoff)
- sde_splash_clean_up_exit_lk(kms);
+ if (sde_kms->splash_info.handoff &&
+ sde_kms->splash_info.display_splash_enabled)
+ sde_splash_lk_stop_splash(kms);
else
sde_power_resource_enable(&priv->phandle,
sde_kms->core_client, true);
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index de0551b22d2e..6055dc861c72 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include "sde_encoder.h"
#include "sde_connector.h"
#include "sde_hw_sspp.h"
+#include "sde_splash.h"
#define RESERVED_BY_OTHER(h, r) \
((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id))
@@ -417,6 +418,8 @@ int sde_rm_init(struct sde_rm *rm,
mutex_init(&rm->rm_lock);
+ rm->dev = dev;
+
INIT_LIST_HEAD(&rm->rsvps);
for (type = 0; type < SDE_HW_BLK_MAX; type++)
INIT_LIST_HEAD(&rm->hw_blks[type]);
@@ -652,7 +655,8 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
static int _sde_rm_reserve_lms(
struct sde_rm *rm,
struct sde_rm_rsvp *rsvp,
- struct sde_rm_requirements *reqs)
+ struct sde_rm_requirements *reqs,
+ uint32_t prefer_lm_id)
{
struct sde_rm_hw_blk *lm[MAX_BLOCKS];
@@ -678,6 +682,10 @@ static int _sde_rm_reserve_lms(
lm_count = 0;
lm[lm_count] = iter_i.blk;
+ /* find the matched lm id */
+ if ((prefer_lm_id > 0) && (iter_i.blk->id != prefer_lm_id))
+ continue;
+
if (!_sde_rm_check_lm_and_get_connected_blks(rm, rsvp, reqs,
lm[lm_count], &dspp[lm_count], &pp[lm_count],
NULL))
@@ -699,6 +707,7 @@ static int _sde_rm_reserve_lms(
continue;
lm[lm_count] = iter_j.blk;
+
++lm_count;
}
}
@@ -747,7 +756,8 @@ static int _sde_rm_reserve_lms(
static int _sde_rm_reserve_ctls(
struct sde_rm *rm,
struct sde_rm_rsvp *rsvp,
- struct sde_rm_requirements *reqs)
+ struct sde_rm_requirements *reqs,
+ uint32_t prefer_ctl_id)
{
struct sde_rm_hw_blk *ctls[MAX_BLOCKS];
struct sde_rm_hw_iter iter;
@@ -769,6 +779,14 @@ static int _sde_rm_reserve_ctls(
SDE_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, caps);
+ /* early return when finding the matched ctl id */
+ if ((prefer_ctl_id > 0) && (iter.blk->id == prefer_ctl_id)) {
+ ctls[i] = iter.blk;
+
+ if (++i == reqs->num_ctl)
+ break;
+ }
+
if (reqs->needs_split_display != has_split_display)
continue;
@@ -928,10 +946,10 @@ static int _sde_rm_make_next_rsvp(
* - Check mixers without DSPPs
* - Only then allow to grab from mixers with DSPP capability
*/
- ret = _sde_rm_reserve_lms(rm, rsvp, reqs);
+ ret = _sde_rm_reserve_lms(rm, rsvp, reqs, 0);
if (ret && !RM_RQ_DSPP(reqs)) {
reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DSPP);
- ret = _sde_rm_reserve_lms(rm, rsvp, reqs);
+ ret = _sde_rm_reserve_lms(rm, rsvp, reqs, 0);
}
if (ret) {
@@ -944,10 +962,10 @@ static int _sde_rm_make_next_rsvp(
* - Check mixers without Split Display
* - Only then allow to grab from CTLs with split display capability
*/
- _sde_rm_reserve_ctls(rm, rsvp, reqs);
+ _sde_rm_reserve_ctls(rm, rsvp, reqs, 0);
if (ret && !reqs->needs_split_display) {
reqs->needs_split_display = true;
- _sde_rm_reserve_ctls(rm, rsvp, reqs);
+ _sde_rm_reserve_ctls(rm, rsvp, reqs, 0);
}
if (ret) {
SDE_ERROR("unable to find appropriate CTL\n");
@@ -962,6 +980,109 @@ static int _sde_rm_make_next_rsvp(
return ret;
}
+static int _sde_rm_make_next_rsvp_for_splash(
+ struct sde_rm *rm,
+ struct drm_encoder *enc,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ struct sde_rm_rsvp *rsvp,
+ struct sde_rm_requirements *reqs)
+{
+ int ret;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+ struct sde_splash_info *sinfo;
+ int i;
+ int intf_id = INTF_0;
+ u32 prefer_lm_id = 0;
+ u32 prefer_ctl_id = 0;
+
+ if (!enc->dev || !enc->dev->dev_private) {
+ SDE_ERROR("drm device invalid\n");
+ return -EINVAL;
+ }
+
+ priv = enc->dev->dev_private;
+ if (!priv->kms) {
+ SDE_ERROR("invalid kms\n");
+ return -EINVAL;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+ sinfo = &sde_kms->splash_info;
+
+ /* Get the intf id first, and reserve the same lk and ctl
+ * in bootloader for kernel resource manager
+ */
+ for (i = 0; i < ARRAY_SIZE(reqs->hw_res.intfs); i++) {
+ if (reqs->hw_res.intfs[i] == INTF_MODE_NONE)
+ continue;
+ intf_id = i + INTF_0;
+ break;
+ }
+
+ /* get preferred lm id and ctl id */
+ for (i = 0; i < CTL_MAX - 1; i++) {
+ if (sinfo->res.top[i].intf_sel != intf_id)
+ continue;
+
+ prefer_lm_id = sinfo->res.top[i].lm[0].lm_id;
+ prefer_ctl_id = sinfo->res.top[i].lm[0].ctl_id;
+ break;
+ }
+
+ SDE_DEBUG("intf_id %d, prefer lm_id %d, ctl_id %d\n",
+ intf_id, prefer_lm_id, prefer_ctl_id);
+
+ /* Create reservation info, tag reserved blocks with it as we go */
+ rsvp->seq = ++rm->rsvp_next_seq;
+ rsvp->enc_id = enc->base.id;
+ rsvp->topology = reqs->top_name;
+ list_add_tail(&rsvp->list, &rm->rsvps);
+
+ /*
+ * Assign LMs and blocks whose usage is tied to them: DSPP & Pingpong.
+ * Do assignment preferring to give away low-resource mixers first:
+ * - Check mixers without DSPPs
+ * - Only then allow to grab from mixers with DSPP capability
+ */
+ ret = _sde_rm_reserve_lms(rm, rsvp, reqs, prefer_lm_id);
+ if (ret && !RM_RQ_DSPP(reqs)) {
+ reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DSPP);
+ ret = _sde_rm_reserve_lms(rm, rsvp, reqs, prefer_lm_id);
+ }
+
+ if (ret) {
+ SDE_ERROR("unable to find appropriate mixers\n");
+ return ret;
+ }
+
+ /*
+ * Do assignment preferring to give away low-resource CTLs first:
+ * - Check mixers without Split Display
+ * - Only then allow to grab from CTLs with split display capability
+ */
+ for (i = 0; i < sinfo->res.ctl_top_cnt; i++)
+ SDE_DEBUG("splash_info ctl_ids[%d] = %d\n",
+ i, sinfo->res.ctl_ids[i]);
+
+ ret = _sde_rm_reserve_ctls(rm, rsvp, reqs, prefer_ctl_id);
+ if (ret && !reqs->needs_split_display) {
+ reqs->needs_split_display = true;
+ _sde_rm_reserve_ctls(rm, rsvp, reqs, prefer_ctl_id);
+ }
+
+ if (ret) {
+ SDE_ERROR("unable to find appropriate CTL\n");
+ return ret;
+ }
+
+ /* Assign INTFs, WBs, and blks whose usage is tied to them: CTL & CDM */
+ ret = _sde_rm_reserve_intf_related_hw(rm, rsvp, &reqs->hw_res);
+
+ return ret;
+}
+
static int _sde_rm_populate_requirements(
struct sde_rm *rm,
struct drm_encoder *enc,
@@ -1253,6 +1374,8 @@ int sde_rm_reserve(
{
struct sde_rm_rsvp *rsvp_cur, *rsvp_nxt;
struct sde_rm_requirements reqs;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
int ret;
if (!rm || !enc || !crtc_state || !conn_state) {
@@ -1260,6 +1383,19 @@ int sde_rm_reserve(
return -EINVAL;
}
+ if (!enc->dev || !enc->dev->dev_private) {
+ SDE_ERROR("invalid drm device\n");
+ return -EINVAL;
+ }
+
+ priv = enc->dev->dev_private;
+ if (!priv->kms) {
+ SDE_ERROR("invald kms\n");
+ return -EINVAL;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+
/* Check if this is just a page-flip */
if (!drm_atomic_crtc_needs_modeset(crtc_state))
return 0;
@@ -1318,8 +1454,13 @@ int sde_rm_reserve(
}
/* Check the proposed reservation, store it in hw's "next" field */
- ret = _sde_rm_make_next_rsvp(rm, enc, crtc_state, conn_state,
- rsvp_nxt, &reqs);
+ if (sde_kms->splash_info.handoff) {
+ SDE_DEBUG("Reserve resource for splash\n");
+ ret = _sde_rm_make_next_rsvp_for_splash
+ (rm, enc, crtc_state, conn_state, rsvp_nxt, &reqs);
+ } else
+ ret = _sde_rm_make_next_rsvp(rm, enc, crtc_state, conn_state,
+ rsvp_nxt, &reqs);
_sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_RSVPNEXT);
@@ -1352,3 +1493,92 @@ end:
return ret;
}
+
+static int _sde_rm_get_ctl_lm_for_splash(struct sde_hw_ctl *ctl,
+ int max_lm_cnt, u8 lm_cnt, u8 *lm_ids,
+ struct splash_ctl_top *top, int index)
+{
+ int j;
+ struct splash_lm_hw *lm;
+
+ if (!ctl || !top) {
+ SDE_ERROR("invalid parameters\n");
+ return 0;
+ }
+
+ lm = top->lm;
+ for (j = 0; j < max_lm_cnt; j++) {
+ lm[top->ctl_lm_cnt].lm_reg_value =
+ ctl->ops.read_ctl_layers_for_splash(ctl, j + LM_0);
+
+ if (lm[top->ctl_lm_cnt].lm_reg_value) {
+ lm[top->ctl_lm_cnt].ctl_id = index + CTL_0;
+ lm_ids[lm_cnt++] = j + LM_0;
+ lm[top->ctl_lm_cnt].lm_id = j + LM_0;
+ top->ctl_lm_cnt++;
+ }
+ }
+
+ return top->ctl_lm_cnt;
+}
+
+static void _sde_rm_get_ctl_top_for_splash(struct sde_hw_ctl *ctl,
+ struct splash_ctl_top *top)
+{
+ if (!ctl || !top) {
+ SDE_ERROR("invalid ctl or top\n");
+ return;
+ }
+
+ if (!ctl->ops.read_ctl_top_for_splash) {
+ SDE_ERROR("read_ctl_top not initialized\n");
+ return;
+ }
+
+ top->value = ctl->ops.read_ctl_top_for_splash(ctl);
+ top->intf_sel = (top->value >> 4) & 0xf;
+}
+
+int sde_rm_read_resource_for_splash(struct sde_rm *rm,
+ void *splash_info,
+ struct sde_mdss_cfg *cat)
+{
+ struct sde_rm_hw_iter ctl_iter;
+ int index = 0;
+ struct sde_splash_info *sinfo;
+ struct sde_hw_ctl *ctl;
+
+ if (!rm || !splash_info || !cat)
+ return -EINVAL;
+
+ sinfo = (struct sde_splash_info *)splash_info;
+
+ sde_rm_init_hw_iter(&ctl_iter, 0, SDE_HW_BLK_CTL);
+
+ while (_sde_rm_get_hw_locked(rm, &ctl_iter)) {
+ ctl = (struct sde_hw_ctl *)ctl_iter.hw;
+
+ _sde_rm_get_ctl_top_for_splash(ctl,
+ &sinfo->res.top[index]);
+
+ if (sinfo->res.top[index].intf_sel) {
+ sinfo->res.lm_cnt +=
+ _sde_rm_get_ctl_lm_for_splash(ctl,
+ cat->mixer_count,
+ sinfo->res.lm_cnt,
+ sinfo->res.lm_ids,
+ &sinfo->res.top[index], index);
+
+ sinfo->res.ctl_ids[sinfo->res.ctl_top_cnt] =
+ index + CTL_0;
+
+ sinfo->res.ctl_top_cnt++;
+ }
+ index++;
+ }
+
+ SDE_DEBUG("%s: ctl_top_cnt=%d, lm_cnt=%d\n", __func__,
+ sinfo->res.ctl_top_cnt, sinfo->res.lm_cnt);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.h b/drivers/gpu/drm/msm/sde/sde_rm.h
index 87e95bfebe98..bec398a3b996 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.h
+++ b/drivers/gpu/drm/msm/sde/sde_rm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -212,4 +212,14 @@ int sde_rm_check_property_topctl(uint64_t val);
*/
int sde_rm_check_property_topctl(uint64_t val);
+/**
+ * sde_rm_read_resource_for_splash - read splash resource used in bootloader
+ * @rm: SDE Resource Manager handle
+ * @sinfo: handle for splash info
+ * @cat: Pointer to hardware catalog
+ */
+int sde_rm_read_resource_for_splash(struct sde_rm *rm,
+ void *sinfo,
+ struct sde_mdss_cfg *cat);
+
#endif /* __SDE_RM_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_splash.c b/drivers/gpu/drm/msm/sde/sde_splash.c
index f6bd7b040dcb..f124bd7d5904 100644
--- a/drivers/gpu/drm/msm/sde/sde_splash.c
+++ b/drivers/gpu/drm/msm/sde/sde_splash.c
@@ -22,6 +22,7 @@
#include "sde_hw_util.h"
#include "sde_hw_intf.h"
#include "sde_hw_catalog.h"
+#include "sde_rm.h"
#include "dsi_display.h"
#include "sde_hdmi.h"
@@ -35,11 +36,9 @@
#define SCRATCH_REGISTER_2 0x01C
#define SDE_LK_RUNNING_VALUE 0xC001CAFE
-#define SDE_LK_SHUT_DOWN_VALUE 0xDEADDEAD
+#define SDE_LK_STOP_SPLASH_VALUE 0xDEADDEAD
#define SDE_LK_EXIT_VALUE 0xDEADBEEF
-#define SDE_LK_EXIT_MAX_LOOP 20
-
#define INTF_HDMI_SEL (BIT(25) | BIT(24))
#define INTF_DSI0_SEL BIT(8)
#define INTF_DSI1_SEL BIT(16)
@@ -189,26 +188,14 @@ static bool _sde_splash_lk_check(struct sde_hw_intr *intr)
}
/**
- * _sde_splash_notify_lk_to_exit.
+ * _sde_splash_notify_lk_stop_splash.
*
- * Function to monitor LK's status and tell it to exit.
+ * Function to stop early splash in LK.
*/
-static void _sde_splash_notify_lk_exit(struct sde_hw_intr *intr)
+static inline void _sde_splash_notify_lk_stop_splash(struct sde_hw_intr *intr)
{
- int i = 0;
-
- /* first is to write exit signal to scratch register*/
- SDE_REG_WRITE(&intr->hw, SCRATCH_REGISTER_1, SDE_LK_SHUT_DOWN_VALUE);
-
- while ((SDE_LK_EXIT_VALUE !=
- SDE_REG_READ(&intr->hw, SCRATCH_REGISTER_1)) &&
- (++i < SDE_LK_EXIT_MAX_LOOP)) {
- DRM_INFO("wait for LK's exit");
- msleep(20);
- }
-
- if (i == SDE_LK_EXIT_MAX_LOOP)
- SDE_ERROR("Loop LK's exit failed\n");
+ /* write splash stop signal to scratch register*/
+ SDE_REG_WRITE(&intr->hw, SCRATCH_REGISTER_1, SDE_LK_STOP_SPLASH_VALUE);
}
static int _sde_splash_gem_new(struct drm_device *dev,
@@ -326,31 +313,28 @@ static void _sde_splash_sent_pipe_update_uevent(struct sde_kms *sde_kms)
kfree(event_string);
}
-static void _sde_splash_get_connector_ref_cnt(struct sde_splash_info *sinfo,
- u32 *hdmi_cnt, u32 *dsi_cnt)
+static int _sde_splash_free_module_resource(struct msm_mmu *mmu,
+ struct sde_splash_info *sinfo)
{
- mutex_lock(&sde_splash_lock);
- *hdmi_cnt = sinfo->hdmi_connector_cnt;
- *dsi_cnt = sinfo->dsi_connector_cnt;
- mutex_unlock(&sde_splash_lock);
-}
+ int i = 0;
+ struct msm_gem_object *msm_obj;
-static int _sde_splash_free_resource(struct msm_mmu *mmu,
- struct sde_splash_info *sinfo, enum splash_connector_type conn)
-{
- struct msm_gem_object *msm_obj = to_msm_bo(sinfo->obj[conn]);
+ for (i = 0; i < sinfo->splash_mem_num; i++) {
+ msm_obj = to_msm_bo(sinfo->obj[i]);
- if (!msm_obj)
- return -EINVAL;
+ if (!msm_obj)
+ return -EINVAL;
- if (mmu->funcs && mmu->funcs->unmap)
- mmu->funcs->early_splash_unmap(mmu,
- sinfo->splash_mem_paddr[conn], msm_obj->sgt);
+ if (mmu->funcs && mmu->funcs->unmap)
+ mmu->funcs->early_splash_unmap(mmu,
+ sinfo->splash_mem_paddr[i], msm_obj->sgt);
- _sde_splash_free_bootup_memory_to_system(sinfo->splash_mem_paddr[conn],
- sinfo->splash_mem_size[conn]);
+ _sde_splash_free_bootup_memory_to_system(
+ sinfo->splash_mem_paddr[i],
+ sinfo->splash_mem_size[i]);
- _sde_splash_destroy_gem_object(msm_obj);
+ _sde_splash_destroy_gem_object(msm_obj);
+ }
return 0;
}
@@ -359,6 +343,7 @@ __ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms)
{
struct sde_kms *sde_kms;
struct sde_splash_info *sinfo;
+ int ret = 0;
int i = 0;
if (!phandle || !kms) {
@@ -372,22 +357,27 @@ __ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms)
sinfo->dsi_connector_cnt = 0;
sinfo->hdmi_connector_cnt = 0;
+ /* Vote data bus after splash is enabled in bootloader */
sde_power_data_bus_bandwidth_ctrl(phandle,
sde_kms->core_client, true);
for (i = 0; i < sinfo->splash_mem_num; i++) {
if (!memblock_is_reserved(sinfo->splash_mem_paddr[i])) {
- SDE_ERROR("failed to reserve memory\n");
+ SDE_ERROR("LK's splash memory is not reserved\n");
/* withdraw the vote when failed. */
sde_power_data_bus_bandwidth_ctrl(phandle,
sde_kms->core_client, false);
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
}
- return 0;
+ ret = sde_rm_read_resource_for_splash(&sde_kms->rm,
+ (void *)sinfo, sde_kms->catalog);
+
+ return ret;
}
void sde_splash_destroy(struct sde_splash_info *sinfo,
@@ -572,12 +562,12 @@ int sde_splash_get_handoff_status(struct msm_kms *kms)
if (num_of_display_on) {
sinfo->handoff = true;
- sinfo->program_scratch_regs = true;
+ sinfo->display_splash_enabled = true;
sinfo->lk_is_exited = false;
sinfo->intf_sel_status = intf_sel;
} else {
sinfo->handoff = false;
- sinfo->program_scratch_regs = false;
+ sinfo->display_splash_enabled = false;
sinfo->lk_is_exited = true;
}
@@ -703,29 +693,34 @@ void sde_splash_setup_connector_count(struct sde_splash_info *sinfo,
}
}
-bool sde_splash_get_lk_complete_status(struct sde_splash_info *sinfo)
+bool sde_splash_get_lk_complete_status(struct msm_kms *kms)
{
- bool ret = 0;
+ struct sde_kms *sde_kms = to_sde_kms(kms);
+ struct sde_hw_intr *intr;
- mutex_lock(&sde_splash_lock);
- ret = !sinfo->handoff && !sinfo->lk_is_exited;
- mutex_unlock(&sde_splash_lock);
+ if (!sde_kms || !sde_kms->hw_intr) {
+ SDE_ERROR("invalid kms\n");
+ return false;
+ }
- return ret;
+ intr = sde_kms->hw_intr;
+
+ if (sde_kms->splash_info.handoff &&
+ SDE_LK_EXIT_VALUE == SDE_REG_READ(&intr->hw,
+ SCRATCH_REGISTER_1)) {
+ SDE_DEBUG("LK totoally exits\n");
+ return true;
+ }
+
+ return false;
}
-int sde_splash_clean_up_free_resource(struct msm_kms *kms,
- struct sde_power_handle *phandle,
- int connector_type, void *display)
+int sde_splash_free_resource(struct msm_kms *kms,
+ struct sde_power_handle *phandle)
{
struct sde_kms *sde_kms;
struct sde_splash_info *sinfo;
struct msm_mmu *mmu;
- struct dsi_display *dsi_display = display;
- int ret = 0;
- int hdmi_conn_count = 0;
- int dsi_conn_count = 0;
- static const char *last_commit_display_type = "unknown";
if (!phandle || !kms) {
SDE_ERROR("invalid phandle/kms.\n");
@@ -739,88 +734,49 @@ int sde_splash_clean_up_free_resource(struct msm_kms *kms,
return -EINVAL;
}
- _sde_splash_get_connector_ref_cnt(sinfo, &hdmi_conn_count,
- &dsi_conn_count);
-
mutex_lock(&sde_splash_lock);
- if (hdmi_conn_count == 0 && dsi_conn_count == 0 &&
- !sinfo->lk_is_exited) {
- /* When both hdmi's and dsi's handoff are finished,
- * 1. Destroy splash node objects.
- * 2. Release the memory which LK's stack is running on.
- * 3. Withdraw AHB data bus bandwidth voting.
- */
- DRM_INFO("HDMI and DSI resource handoff is completed\n");
-
- sinfo->lk_is_exited = true;
-
- _sde_splash_destroy_splash_node(sinfo);
-
- _sde_splash_free_bootup_memory_to_system(sinfo->lk_pool_paddr,
- sinfo->lk_pool_size);
-
- sde_power_data_bus_bandwidth_ctrl(phandle,
- sde_kms->core_client, false);
-
- _sde_splash_sent_pipe_update_uevent(sde_kms);
-
+ if (!sinfo->handoff) {
mutex_unlock(&sde_splash_lock);
return 0;
}
mmu = sde_kms->aspace[0]->mmu;
+ if (!mmu) {
+ mutex_unlock(&sde_splash_lock);
+ return -EINVAL;
+ }
- switch (connector_type) {
- case DRM_MODE_CONNECTOR_HDMIA:
- if (sinfo->hdmi_connector_cnt == 1) {
- sinfo->hdmi_connector_cnt--;
+ /* free HDMI's, DSI's and early camera's reserved memory */
+ _sde_splash_free_module_resource(mmu, sinfo);
- ret = _sde_splash_free_resource(mmu,
- sinfo, SPLASH_HDMI);
- }
- break;
- case DRM_MODE_CONNECTOR_DSI:
- /*
- * Basically, we have commits coming on two DSI connectors.
- * So when releasing DSI resource, it's ensured that the
- * coming commits should happen on different DSIs, to promise
- * the handoff has finished on the two DSIs, then it's safe
- * to release DSI resource, otherwise, problem happens when
- * freeing memory, while DSI0 or DSI1 is still visiting
- * the memory.
- */
- if (strcmp(dsi_display->display_type, "unknown") &&
- strcmp(last_commit_display_type,
- dsi_display->display_type)) {
- if (sinfo->dsi_connector_cnt > 1)
- sinfo->dsi_connector_cnt--;
- else if (sinfo->dsi_connector_cnt == 1) {
- ret = _sde_splash_free_resource(mmu,
- sinfo, SPLASH_DSI);
-
- sinfo->dsi_connector_cnt--;
- }
+ _sde_splash_destroy_splash_node(sinfo);
- last_commit_display_type = dsi_display->display_type;
- }
- break;
- default:
- ret = -EINVAL;
- SDE_ERROR("%s: invalid connector_type %d\n",
- __func__, connector_type);
- }
+ /* free lk_pool heap memory */
+ _sde_splash_free_bootup_memory_to_system(sinfo->lk_pool_paddr,
+ sinfo->lk_pool_size);
- mutex_unlock(&sde_splash_lock);
+ /* withdraw data bus vote */
+ sde_power_data_bus_bandwidth_ctrl(phandle,
+ sde_kms->core_client, false);
- return ret;
+ /* send uevent to notify user to recycle resource */
+ _sde_splash_sent_pipe_update_uevent(sde_kms);
+
+ /* Finally mark handoff flag to false to say handoff is complete */
+ sinfo->handoff = false;
+
+ DRM_INFO("HDMI and DSI resource handoff is completed\n");
+
+ mutex_unlock(&sde_splash_lock);
+ return 0;
}
/*
* In below function, it will
- * 1. Notify LK to exit and wait for exiting is done.
+ * 1. Notify LK to stop display splash.
* 2. Set DOMAIN_ATTR_EARLY_MAP to 1 to enable stage 1 translation in iommu.
*/
-int sde_splash_clean_up_exit_lk(struct msm_kms *kms)
+int sde_splash_lk_stop_splash(struct msm_kms *kms)
{
struct sde_splash_info *sinfo;
struct msm_mmu *mmu;
@@ -836,12 +792,11 @@ int sde_splash_clean_up_exit_lk(struct msm_kms *kms)
/* Monitor LK's status and tell it to exit. */
mutex_lock(&sde_splash_lock);
- if (sinfo->program_scratch_regs) {
+ if (sinfo->display_splash_enabled) {
if (_sde_splash_lk_check(sde_kms->hw_intr))
- _sde_splash_notify_lk_exit(sde_kms->hw_intr);
+ _sde_splash_notify_lk_stop_splash(sde_kms->hw_intr);
- sinfo->handoff = false;
- sinfo->program_scratch_regs = false;
+ sinfo->display_splash_enabled = false;
}
mutex_unlock(&sde_splash_lock);
@@ -858,7 +813,8 @@ int sde_splash_clean_up_exit_lk(struct msm_kms *kms)
*/
if (mmu->funcs && mmu->funcs->set_property) {
ret = mmu->funcs->set_property(mmu,
- DOMAIN_ATTR_EARLY_MAP, &sinfo->handoff);
+ DOMAIN_ATTR_EARLY_MAP,
+ &sinfo->display_splash_enabled);
if (ret)
SDE_ERROR("set_property failed\n");
diff --git a/drivers/gpu/drm/msm/sde/sde_splash.h b/drivers/gpu/drm/msm/sde/sde_splash.h
index 9eddd87e5e26..2fd8ba03112f 100644
--- a/drivers/gpu/drm/msm/sde/sde_splash.h
+++ b/drivers/gpu/drm/msm/sde/sde_splash.h
@@ -15,18 +15,46 @@
#include "msm_kms.h"
#include "msm_mmu.h"
+#include "sde_hw_mdss.h"
+
+#define SPLASH_CTL_MAX 5
+#define SPLASH_LM_MAX 7
enum splash_connector_type {
SPLASH_DSI = 0,
SPLASH_HDMI,
};
+struct splash_lm_hw {
+ u8 lm_id;
+ u8 ctl_id;
+ u32 lm_reg_value;
+};
+
+struct splash_ctl_top {
+ u32 value;
+ u8 intf_sel;
+ u8 ctl_lm_cnt;
+ struct splash_lm_hw lm[SPLASH_LM_MAX];
+};
+
+struct sde_res_data {
+ struct splash_ctl_top top[SPLASH_CTL_MAX];
+ u8 ctl_ids[SPLASH_CTL_MAX];
+ u8 lm_ids[SPLASH_LM_MAX];
+ u8 ctl_top_cnt;
+ u8 lm_cnt;
+};
+
struct sde_splash_info {
/* handoff flag */
bool handoff;
- /* flag of display scratch registers */
- bool program_scratch_regs;
+ /* current hw configuration */
+ struct sde_res_data res;
+
+ /* flag of display splash status */
+ bool display_splash_enabled;
/* to indicate LK is totally exited */
bool lk_is_exited;
@@ -91,21 +119,20 @@ void sde_splash_setup_connector_count(struct sde_splash_info *sinfo,
int connector_type);
/**
- * sde_splash_clean_up_exit_lk.
+ * sde_splash_lk_stop_splash.
*
- * Tell LK to exit, and clean up the resource.
+ * Tell LK to stop display splash.
*/
-int sde_splash_clean_up_exit_lk(struct msm_kms *kms);
+int sde_splash_lk_stop_splash(struct msm_kms *kms);
/**
- * sde_splash_clean_up_free_resource.
+ * sde_splash_free_resource.
*
* According to input connector_type, free
* HDMI's and DSI's resource respectively.
*/
-int sde_splash_clean_up_free_resource(struct msm_kms *kms,
- struct sde_power_handle *phandle,
- int connector_type, void *display);
+int sde_splash_free_resource(struct msm_kms *kms,
+ struct sde_power_handle *phandle);
/**
* sde_splash_parse_memory_dt.
@@ -152,7 +179,7 @@ void sde_splash_destroy(struct sde_splash_info *sinfo,
*
* Get LK's status to check if it has been stopped.
*/
-bool sde_splash_get_lk_complete_status(struct sde_splash_info *sinfo);
+bool sde_splash_get_lk_complete_status(struct msm_kms *kms);
/**
* sde_splash_setup_display_resource