diff --git a/msm/Makefile b/msm/Makefile index 2de1420ec6..3b4d225945 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -69,6 +69,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_dsc.o \ sde/sde_hw_ds.o \ sde/sde_fence.o \ + sde/sde_hw_qdss.o \ msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o \ diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 0515201608..090f9163a5 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -417,6 +417,18 @@ struct dsi_mode_info { struct msm_roi_caps roi_caps; }; +/** + * struct dsi_split_link_config - Split Link Configuration + * @split_link_enabled: Split Link Enabled. + * @num_sublinks: Number of sublinks. + * @lanes_per_sublink: Number of lanes per sublink. + */ +struct dsi_split_link_config { + bool split_link_enabled; + u32 num_sublinks; + u32 lanes_per_sublink; +}; + /** * struct dsi_host_common_cfg - Host configuration common to video and cmd mode * @dst_format: Destination pixel format. @@ -444,6 +456,7 @@ struct dsi_mode_info { * true. * @ext_bridge_mode: External bridge is connected. * @force_hs_clk_lane: Send continuous clock to the panel. + * @dsi_split_link_config: Split Link Configuration. */ struct dsi_host_common_cfg { enum dsi_pixel_format dst_format; @@ -466,6 +479,7 @@ struct dsi_host_common_cfg { bool append_tx_eot; bool ext_bridge_mode; bool force_hs_clk_lane; + struct dsi_split_link_config split_link; }; /** diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index fbe000a73a..44929c0903 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -5403,6 +5403,7 @@ int dsi_display_get_info(struct drm_connector *connector, { struct dsi_display *display; struct dsi_panel_phy_props phy_props; + struct dsi_host_common_cfg *host; int i, rc; if (!info || !disp) { @@ -5470,6 +5471,9 @@ int dsi_display_get_info(struct drm_connector *connector, info->te_source = display->te_source; + host = &display->panel->host_config; + if (host->split_link.split_link_enabled) + info->capabilities |= MSM_DISPLAY_SPLIT_LINK; error: mutex_unlock(&display->display_lock); return rc; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index c8c490d954..240e10a54e 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -238,6 +238,7 @@ enum msm_display_compression_ratio { * @MSM_DISPLAY_CAP_EDID: EDID supported * @MSM_DISPLAY_ESD_ENABLED: ESD feature enabled * @MSM_DISPLAY_CAP_MST_MODE: Display with MST support + * @MSM_DISPLAY_SPLIT_LINK: Split Link enabled */ enum msm_display_caps { MSM_DISPLAY_CAP_VID_MODE = BIT(0), @@ -246,6 +247,7 @@ enum msm_display_caps { MSM_DISPLAY_CAP_EDID = BIT(3), MSM_DISPLAY_ESD_ENABLED = BIT(4), MSM_DISPLAY_CAP_MST_MODE = BIT(5), + MSM_DISPLAY_SPLIT_LINK = BIT(6), }; /** diff --git a/msm/msm_gem_vma.c b/msm/msm_gem_vma.c index 3d3c62db5a..2240f774dd 100644 --- a/msm/msm_gem_vma.c +++ b/msm/msm_gem_vma.c @@ -69,6 +69,7 @@ static void smmu_aspace_add_to_active( { WARN_ON(!mutex_is_locked(&aspace->list_lock)); list_move_tail(&msm_obj->iova_list, &aspace->active_list); + msm_obj->in_active_list = true; } static void smmu_aspace_remove_from_active( @@ -82,6 +83,7 @@ static void smmu_aspace_remove_from_active( list_for_each_entry_safe(msm_obj, next, &aspace->active_list, iova_list) { if (msm_obj == obj) { + msm_obj->in_active_list = false; list_del(&msm_obj->iova_list); break; } diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 9f18b09830..9973c05f51 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -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); diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index e43eefc6f9..02f359e8de 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -250,6 +250,7 @@ struct sde_encoder_irq { * @hw_ctl: Hardware interface to the ctl registers * @hw_intf: Hardware interface to INTF registers * @hw_cdm: Hardware interface to the cdm registers + * @hw_qdss: Hardware interface to the qdss registers * @cdm_cfg: Chroma-down hardware configuration * @hw_pp: Hardware interface to the ping pong registers * @sde_kms: Pointer to the sde_kms top level @@ -298,6 +299,7 @@ struct sde_encoder_phys { struct sde_hw_ctl *hw_ctl; struct sde_hw_intf *hw_intf; struct sde_hw_cdm *hw_cdm; + struct sde_hw_qdss *hw_qdss; struct sde_hw_cdm_cfg cdm_cfg; struct sde_hw_pingpong *hw_pp; struct sde_kms *sde_kms; diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 41eb834b97..1102caf8f6 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -385,8 +385,10 @@ static void sde_encoder_phys_vid_setup_timing_engine( u32 qsync_min_fps = 0; unsigned long lock_flags; struct sde_hw_intf_cfg intf_cfg = { 0 }; + bool is_split_link = false; - if (!phys_enc || !phys_enc->sde_kms || !phys_enc->hw_ctl) { + if (!phys_enc || !phys_enc->sde_kms || !phys_enc->hw_ctl || + !phys_enc->hw_intf) { SDE_ERROR("invalid encoder %d\n", !phys_enc); return; } @@ -401,7 +403,8 @@ static void sde_encoder_phys_vid_setup_timing_engine( SDE_DEBUG_VIDENC(vid_enc, "enabling mode:\n"); drm_mode_debug_printmodeline(&mode); - if (phys_enc->split_role != ENC_ROLE_SOLO) { + is_split_link = phys_enc->hw_intf->cfg.split_link_en; + if (phys_enc->split_role != ENC_ROLE_SOLO || is_split_link) { mode.hdisplay >>= 1; mode.htotal >>= 1; mode.hsync_start >>= 1; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index e3d575c2f1..fb9222d298 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -3641,7 +3641,8 @@ end: return rc; } -int sde_qdss_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) +static int sde_qdss_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[HW_PROP_MAX], i; struct sde_prop_value *prop_value = NULL; diff --git a/msm/sde/sde_hw_interrupts.c b/msm/sde/sde_hw_interrupts.c index fdbd5c0ad7..5616d1f286 100644 --- a/msm/sde/sde_hw_interrupts.c +++ b/msm/sde/sde_hw_interrupts.c @@ -308,6 +308,8 @@ static struct sde_irq_type sde_irq_intr2_map[] = { { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_S0, SDE_INTR_PING_PONG_S0_WR_PTR, -1}, + { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_1, SDE_INTR_CWB_1_OVERFLOW, -1}, + { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0, SDE_INTR_PING_PONG_S0_RD_PTR, -1}, diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 454d47cbe4..00ebaec926 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -8,7 +8,6 @@ #include "sde_hw_catalog.h" #include "sde_hw_intf.h" #include "sde_dbg.h" -#include "sde_kms.h" #define INTF_TIMING_ENGINE_EN 0x000 #define INTF_CONFIG 0x004 @@ -45,6 +44,7 @@ #define INTF_DEFLICKER_STRNG_COEFF 0x0F4 #define INTF_DEFLICKER_WEAK_COEFF 0x0F8 +#define INTF_REG_SPLIT_LINK 0x080 #define INTF_DSI_CMD_MODE_TRIGGER_EN 0x084 #define INTF_PANEL_FORMAT 0x090 #define INTF_TPG_ENABLE 0x100 @@ -294,6 +294,9 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, if (p->wide_bus_en) intf_cfg2 |= BIT(0); + if (ctx->cfg.split_link_en) + SDE_REG_WRITE(c, INTF_REG_SPLIT_LINK, 0x3); + SDE_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl); SDE_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); SDE_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0, @@ -370,6 +373,9 @@ static void sde_hw_intf_bind_pingpong_blk( else mux_cfg |= 0xf; + if (intf->cfg.split_link_en) + mux_cfg = 0x60000; + SDE_REG_WRITE(c, INTF_MUX, mux_cfg); } diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index a77b8a35ed..7463037a6e 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -10,6 +10,7 @@ #include "sde_hw_mdss.h" #include "sde_hw_util.h" #include "sde_hw_blk.h" +#include "sde_kms.h" struct sde_hw_intf; @@ -186,6 +187,7 @@ struct sde_hw_intf { enum sde_intf idx; const struct sde_intf_cfg *cap; const struct sde_mdss_cfg *mdss; + struct split_pipe_cfg cfg; /* ops */ struct sde_hw_intf_ops ops; diff --git a/msm/sde/sde_hw_top.c b/msm/sde/sde_hw_top.c index 25c0237434..7c2de6c3d0 100644 --- a/msm/sde/sde_hw_top.c +++ b/msm/sde/sde_hw_top.c @@ -127,12 +127,16 @@ static void sde_hw_setup_pp_split(struct sde_hw_mdp *mdp, if (!mdp || !cfg) return; - if (cfg->en && cfg->pp_split_slave != INTF_MAX) { + if (cfg->split_link_en) { + ppb_config |= BIT(16); /* split enable */ + ppb_control = BIT(5); /* horz split*/ + } else if (cfg->en && cfg->pp_split_slave != INTF_MAX) { ppb_config |= (cfg->pp_split_slave - INTF_0 + 1) << 20; ppb_config |= BIT(16); /* split enable */ ppb_control = BIT(5); /* horz split*/ } - if (cfg->pp_split_index) { + + if (cfg->pp_split_index && !cfg->split_link_en) { SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, 0x0); SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, 0x0); SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, ppb_config); @@ -430,6 +434,18 @@ static void sde_hw_intf_audio_select(struct sde_hw_mdp *mdp) SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1); } +static void sde_hw_mdp_events(struct sde_hw_mdp *mdp, bool enable) +{ + struct sde_hw_blk_reg_map *c; + + if (!mdp) + return; + + c = &mdp->hw; + + SDE_REG_WRITE(c, HW_EVENTS_CTL, enable); +} + struct sde_hw_sid *sde_hw_sid_init(void __iomem *addr, u32 sid_len, const struct sde_mdss_cfg *m) { @@ -512,6 +528,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, ops->setup_dce = sde_hw_setup_dce; ops->reset_ubwc = sde_hw_reset_ubwc; ops->intf_audio_select = sde_hw_intf_audio_select; + ops->set_mdp_hw_events = sde_hw_mdp_events; if (cap & BIT(SDE_MDP_VSYNC_SEL)) ops->setup_vsync_source = sde_hw_setup_vsync_source; else diff --git a/msm/sde/sde_hw_top.h b/msm/sde/sde_hw_top.h index 71c2c63636..bda4da7de6 100644 --- a/msm/sde/sde_hw_top.h +++ b/msm/sde/sde_hw_top.h @@ -38,6 +38,7 @@ struct traffic_shaper_cfg { * @pp_split_idx: Ping pong index for ping pong split * @split_flush_en: Allows both the paths to be flushed when master path is * flushed + * @split_link_en: Check if split link is enabled */ struct split_pipe_cfg { bool en; @@ -46,6 +47,7 @@ struct split_pipe_cfg { enum sde_intf pp_split_slave; u32 pp_split_index; bool split_flush_en; + bool split_link_en; }; /** @@ -188,6 +190,13 @@ struct sde_hw_mdp_ops { */ void (*intf_audio_select)(struct sde_hw_mdp *mdp); + /** + * set_mdp_hw_events - enable qdss hardware events for mdp + * @mdp: mdp top context driver + * @enable: enable/disable hw events + */ + void (*set_mdp_hw_events)(struct sde_hw_mdp *mdp, bool enable); + /** * set_cwb_ppb_cntl - select the data point for CWB * @mdp: mdp top context driver diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 019308404d..5beba3c1a3 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -145,6 +145,10 @@ static int _sde_debugfs_init(struct sde_kms *sde_kms) return rc; } + if (sde_kms->catalog->qdss_count) + debugfs_create_u32("qdss", 0600, debugfs_root, + (u32 *)&sde_kms->qdss_enabled); + return 0; } diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index e65aa86206..909c3b0ae1 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -287,6 +287,7 @@ struct sde_kms { struct mutex secure_transition_lock; bool first_kickoff; + bool qdss_enabled; }; struct vsync_info { diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index 91fadd197a..60d3e65074 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -17,6 +17,7 @@ #include "sde_connector.h" #include "sde_hw_dsc.h" #include "sde_crtc.h" +#include "sde_hw_qdss.h" #define RESERVED_BY_OTHER(h, r) \ (((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id)) ||\ @@ -322,6 +323,9 @@ static void _sde_rm_hw_destroy(enum sde_hw_blk_type type, void *hw) case SDE_HW_BLK_DSC: sde_hw_dsc_destroy(hw); break; + case SDE_HW_BLK_QDSS: + sde_hw_qdss_destroy(hw); + break; case SDE_HW_BLK_SSPP: /* SSPPs are not managed by the resource manager */ case SDE_HW_BLK_TOP: @@ -410,6 +414,9 @@ static int _sde_rm_hw_blk_create( case SDE_HW_BLK_DSC: hw = sde_hw_dsc_init(id, mmio, cat); break; + case SDE_HW_BLK_QDSS: + hw = sde_hw_qdss_init(id, mmio, cat); + break; case SDE_HW_BLK_SSPP: /* SSPPs are not managed by the resource manager */ case SDE_HW_BLK_TOP: @@ -525,6 +532,15 @@ static int _sde_rm_hw_blk_create_new(struct sde_rm *rm, } } + for (i = 0; i < cat->qdss_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_QDSS, + cat->qdss[i].id, &cat->qdss[i]); + if (rc) { + SDE_ERROR("failed: qdss hw not available\n"); + goto fail; + } + } + fail: return rc; } @@ -1102,6 +1118,44 @@ static int _sde_rm_reserve_dsc( return -ENAVAIL; } +static int _sde_rm_reserve_qdss( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + const struct sde_rm_topology_def *top, + u8 *_qdss_ids) +{ + struct sde_rm_hw_iter iter; + struct msm_drm_private *priv = rm->dev->dev_private; + struct sde_kms *sde_kms; + + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + sde_kms = to_sde_kms(priv->kms); + + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_QDSS); + + while (_sde_rm_get_hw_locked(rm, &iter)) { + if (RESERVED_BY_OTHER(iter.blk, rsvp)) + continue; + + SDE_DEBUG("blk id = %d\n", iter.blk->id); + + iter.blk->rsvp_nxt = rsvp; + SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id); + return 0; + } + + if (!iter.hw && sde_kms->catalog->qdss_count) { + SDE_DEBUG("couldn't reserve qdss for type %d id %d\n", + SDE_HW_BLK_QDSS, iter.blk->id); + return -ENAVAIL; + } + + return 0; +} + static int _sde_rm_reserve_cdm( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, @@ -1368,6 +1422,10 @@ static int _sde_rm_make_next_rsvp(struct sde_rm *rm, struct drm_encoder *enc, if (ret) return ret; + ret = _sde_rm_reserve_qdss(rm, rsvp, reqs->topology, NULL); + if (ret) + return ret; + return ret; }