|
@@ -37,6 +37,8 @@
|
|
|
#include "sde_crtc.h"
|
|
|
#include "sde_trace.h"
|
|
|
#include "sde_core_irq.h"
|
|
|
+#include "sde_hw_top.h"
|
|
|
+#include "sde_hw_qdss.h"
|
|
|
|
|
|
#define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
|
|
|
(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
|
|
@@ -180,6 +182,7 @@ enum sde_enc_rc_states {
|
|
|
* @intfs_swapped Whether or not the phys_enc interfaces have been swapped
|
|
|
* for partial update right-only cases, such as pingpong
|
|
|
* split where virtual pingpong does not generate IRQs
|
|
|
+ @qdss_status: indicate if qdss is modified since last update
|
|
|
* @crtc_vblank_cb: Callback into the upper layer / CRTC for
|
|
|
* notification of the VBLANK
|
|
|
* @crtc_vblank_cb_data: Data from upper layer for VBLANK notification
|
|
@@ -248,6 +251,7 @@ struct sde_encoder_virt {
|
|
|
enum sde_dsc dirty_dsc_ids[MAX_CHANNELS_PER_ENC];
|
|
|
|
|
|
bool intfs_swapped;
|
|
|
+ bool qdss_status;
|
|
|
|
|
|
void (*crtc_vblank_cb)(void *data);
|
|
|
void *crtc_vblank_cb_data;
|
|
@@ -361,6 +365,20 @@ static bool _sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc)
|
|
|
return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
|
|
|
}
|
|
|
|
|
|
+static void sde_configure_qdss(struct sde_encoder_virt *sde_enc,
|
|
|
+ struct sde_hw_qdss *hw_qdss,
|
|
|
+ struct sde_encoder_phys *phys, bool enable)
|
|
|
+{
|
|
|
+ if (sde_enc->qdss_status == enable)
|
|
|
+ return;
|
|
|
+
|
|
|
+ sde_enc->qdss_status = enable;
|
|
|
+
|
|
|
+ phys->hw_mdptop->ops.set_mdp_hw_events(phys->hw_mdptop,
|
|
|
+ sde_enc->qdss_status);
|
|
|
+ hw_qdss->ops.enable_qdss_events(hw_qdss, sde_enc->qdss_status);
|
|
|
+}
|
|
|
+
|
|
|
static int _sde_encoder_wait_timeout(int32_t drm_id, int32_t hw_id,
|
|
|
s64 timeout_ms, struct sde_encoder_wait_info *info)
|
|
|
{
|
|
@@ -778,7 +796,7 @@ void sde_encoder_helper_split_config(
|
|
|
enum sde_intf interface)
|
|
|
{
|
|
|
struct sde_encoder_virt *sde_enc;
|
|
|
- struct split_pipe_cfg cfg = { 0 };
|
|
|
+ struct split_pipe_cfg *cfg;
|
|
|
struct sde_hw_mdp *hw_mdptop;
|
|
|
enum sde_rm_topology_name topology;
|
|
|
struct msm_display_info *disp_info;
|
|
@@ -791,10 +809,15 @@ void sde_encoder_helper_split_config(
|
|
|
sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
|
|
hw_mdptop = phys_enc->hw_mdptop;
|
|
|
disp_info = &sde_enc->disp_info;
|
|
|
+ cfg = &phys_enc->hw_intf->cfg;
|
|
|
+ memset(cfg, 0, sizeof(*cfg));
|
|
|
|
|
|
if (disp_info->intf_type != DRM_MODE_CONNECTOR_DSI)
|
|
|
return;
|
|
|
|
|
|
+ if (disp_info->capabilities & MSM_DISPLAY_SPLIT_LINK)
|
|
|
+ cfg->split_link_en = true;
|
|
|
+
|
|
|
/**
|
|
|
* disable split modes since encoder will be operating in as the only
|
|
|
* encoder, either for the entire use case in the case of, for example,
|
|
@@ -803,43 +826,43 @@ void sde_encoder_helper_split_config(
|
|
|
*/
|
|
|
if (phys_enc->split_role == ENC_ROLE_SOLO) {
|
|
|
if (hw_mdptop->ops.setup_split_pipe)
|
|
|
- hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
|
|
|
+ hw_mdptop->ops.setup_split_pipe(hw_mdptop, cfg);
|
|
|
if (hw_mdptop->ops.setup_pp_split)
|
|
|
- hw_mdptop->ops.setup_pp_split(hw_mdptop, &cfg);
|
|
|
+ hw_mdptop->ops.setup_pp_split(hw_mdptop, cfg);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- cfg.en = true;
|
|
|
- cfg.mode = phys_enc->intf_mode;
|
|
|
- cfg.intf = interface;
|
|
|
+ cfg->en = true;
|
|
|
+ cfg->mode = phys_enc->intf_mode;
|
|
|
+ cfg->intf = interface;
|
|
|
|
|
|
- if (cfg.en && phys_enc->ops.needs_single_flush &&
|
|
|
+ if (cfg->en && phys_enc->ops.needs_single_flush &&
|
|
|
phys_enc->ops.needs_single_flush(phys_enc))
|
|
|
- cfg.split_flush_en = true;
|
|
|
+ cfg->split_flush_en = true;
|
|
|
|
|
|
topology = sde_connector_get_topology_name(phys_enc->connector);
|
|
|
if (topology == SDE_RM_TOPOLOGY_PPSPLIT)
|
|
|
- cfg.pp_split_slave = cfg.intf;
|
|
|
+ cfg->pp_split_slave = cfg->intf;
|
|
|
else
|
|
|
- cfg.pp_split_slave = INTF_MAX;
|
|
|
+ cfg->pp_split_slave = INTF_MAX;
|
|
|
|
|
|
if (phys_enc->split_role == ENC_ROLE_MASTER) {
|
|
|
- SDE_DEBUG_ENC(sde_enc, "enable %d\n", cfg.en);
|
|
|
+ SDE_DEBUG_ENC(sde_enc, "enable %d\n", cfg->en);
|
|
|
|
|
|
if (hw_mdptop->ops.setup_split_pipe)
|
|
|
- hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
|
|
|
+ hw_mdptop->ops.setup_split_pipe(hw_mdptop, cfg);
|
|
|
} else if (sde_enc->hw_pp[0]) {
|
|
|
/*
|
|
|
* slave encoder
|
|
|
* - determine split index from master index,
|
|
|
* assume master is first pp
|
|
|
*/
|
|
|
- cfg.pp_split_index = sde_enc->hw_pp[0]->idx - PINGPONG_0;
|
|
|
+ cfg->pp_split_index = sde_enc->hw_pp[0]->idx - PINGPONG_0;
|
|
|
SDE_DEBUG_ENC(sde_enc, "master using pp%d\n",
|
|
|
- cfg.pp_split_index);
|
|
|
+ cfg->pp_split_index);
|
|
|
|
|
|
if (hw_mdptop->ops.setup_pp_split)
|
|
|
- hw_mdptop->ops.setup_pp_split(hw_mdptop, &cfg);
|
|
|
+ hw_mdptop->ops.setup_pp_split(hw_mdptop, cfg);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2724,7 +2747,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
|
|
struct drm_connector *conn = NULL, *conn_iter;
|
|
|
struct sde_connector_state *sde_conn_state = NULL;
|
|
|
struct sde_connector *sde_conn = NULL;
|
|
|
- struct sde_rm_hw_iter dsc_iter, pp_iter;
|
|
|
+ struct sde_rm_hw_iter dsc_iter, pp_iter, qdss_iter;
|
|
|
struct sde_rm_hw_request request_hw;
|
|
|
enum sde_intf_mode intf_mode;
|
|
|
|
|
@@ -2826,6 +2849,22 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
|
|
sde_enc->hw_pp[i] = (struct sde_hw_pingpong *) pp_iter.hw;
|
|
|
}
|
|
|
|
|
|
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
|
|
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
|
|
+
|
|
|
+ if (phys) {
|
|
|
+ sde_rm_init_hw_iter(&qdss_iter, drm_enc->base.id,
|
|
|
+ SDE_HW_BLK_QDSS);
|
|
|
+ for (i = 0; i < QDSS_MAX; i++) {
|
|
|
+ if (sde_rm_get_hw(&sde_kms->rm, &qdss_iter)) {
|
|
|
+ phys->hw_qdss =
|
|
|
+ (struct sde_hw_qdss *)qdss_iter.hw;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
sde_rm_init_hw_iter(&dsc_iter, drm_enc->base.id, SDE_HW_BLK_DSC);
|
|
|
for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
|
|
|
sde_enc->hw_dsc[i] = NULL;
|
|
@@ -4601,6 +4640,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
|
|
|
struct sde_encoder_virt *sde_enc;
|
|
|
struct sde_encoder_phys *phys;
|
|
|
struct sde_kms *sde_kms = NULL;
|
|
|
+ struct sde_crtc *sde_crtc;
|
|
|
struct msm_drm_private *priv = NULL;
|
|
|
bool needs_hw_reset = false;
|
|
|
int ln_cnt1 = -EINVAL, i, rc, ret = 0;
|
|
@@ -4615,6 +4655,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
|
|
|
priv = drm_enc->dev->dev_private;
|
|
|
sde_kms = to_sde_kms(priv->kms);
|
|
|
disp_info = &sde_enc->disp_info;
|
|
|
+ sde_crtc = to_sde_crtc(sde_enc->crtc);
|
|
|
|
|
|
SDE_DEBUG_ENC(sde_enc, "\n");
|
|
|
SDE_EVT32(DRMID(drm_enc));
|
|
@@ -4701,6 +4742,10 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
|
|
|
_helper_flush_dsc(sde_enc);
|
|
|
}
|
|
|
|
|
|
+ if (sde_enc->cur_master && !sde_enc->cur_master->cont_splash_enabled)
|
|
|
+ sde_configure_qdss(sde_enc, sde_enc->cur_master->hw_qdss,
|
|
|
+ sde_enc->cur_master, sde_kms->qdss_enabled);
|
|
|
+
|
|
|
end:
|
|
|
SDE_ATRACE_END("sde_encoder_prepare_for_kickoff");
|
|
|
return ret;
|
|
@@ -5518,6 +5563,7 @@ struct drm_encoder *sde_encoder_init_with_ops(
|
|
|
kthread_init_delayed_work(&sde_enc->delayed_off_work,
|
|
|
sde_encoder_off_work);
|
|
|
sde_enc->vblank_enabled = false;
|
|
|
+ sde_enc->qdss_status = false;
|
|
|
|
|
|
kthread_init_work(&sde_enc->vsync_event_work,
|
|
|
sde_encoder_vsync_event_work_handler);
|