summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGuchun Chen <guchunc@codeaurora.org>2018-04-20 19:10:04 +0800
committerGuchun Chen <guchunc@codeaurora.org>2018-05-05 19:01:48 +0800
commit6fb8f903dfe7abb298f38ff301e361ab9acd3fd7 (patch)
tree828636496028e90b0aa5e7431b9bab4ea89e09dc /drivers
parent06af1c706e41c15424c67b81359a5f28de4c1dab (diff)
drm: msm: read SDE registers for splash case
Read sde registers like layer mixer and ctrl information from bootloader when early splash is enabled in bootloader. These information will be updated to kernel resource manager to let bootloader and kernel use the same hardware setting. CRs-Fixed: 2225630 Change-Id: I0e971de1992b380e30933f476b1a7e185ce0ad96 Signed-off-by: Guchun Chen <guchunc@codeaurora.org> Signed-off-by: Camus Wong <camusw@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.c34
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.h15
-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.c12
-rw-r--r--drivers/gpu/drm/msm/sde/sde_splash.h28
6 files changed, 336 insertions, 13 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 9762e69d87e0..341738f624db 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -516,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)
{
@@ -536,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 c0e34bf027f6..a008ecf4a11d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -165,6 +165,21 @@ struct sde_hw_ctl_ops {
void (*setup_blendstage)(struct sde_hw_ctl *ctx,
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_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..71ebb4b37d6b 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"
@@ -359,6 +360,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) {
@@ -377,17 +379,21 @@ __ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms)
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,
diff --git a/drivers/gpu/drm/msm/sde/sde_splash.h b/drivers/gpu/drm/msm/sde/sde_splash.h
index 9eddd87e5e26..0608b2db878d 100644
--- a/drivers/gpu/drm/msm/sde/sde_splash.h
+++ b/drivers/gpu/drm/msm/sde/sde_splash.h
@@ -15,16 +15,44 @@
#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;
+ /* current hw configuration */
+ struct sde_res_data res;
+
/* flag of display scratch registers */
bool program_scratch_regs;