Loading drivers/gpu/drm/msm/sde/sde_encoder.c +43 −12 Original line number Diff line number Diff line Loading @@ -1558,8 +1558,8 @@ static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc, return ret; } static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_display_info *disp_info, bool is_dummy) void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source, bool is_dummy) { struct sde_vsync_source_cfg vsync_cfg = { 0 }; struct msm_drm_private *priv; Loading @@ -1567,11 +1567,11 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct sde_hw_mdp *hw_mdptop; struct drm_encoder *drm_enc; struct msm_mode_info mode_info; struct sde_encoder_virt *sde_enc; int i, rc = 0; if (!sde_enc || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); if (!sde_enc) { SDE_ERROR("invalid param sde_enc:%d\n", sde_enc != NULL); return; } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d\n", Loading @@ -1580,6 +1580,8 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, return; } sde_enc = to_sde_encoder_virt(phys_enc->parent); drm_enc = &sde_enc->base; /* this pointers are checked in virt_enable_helper */ priv = drm_enc->dev->dev_private; Loading @@ -1602,22 +1604,51 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, return; } if (hw_mdptop->ops.setup_vsync_source && disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { if (hw_mdptop->ops.setup_vsync_source) { for (i = 0; i < sde_enc->num_phys_encs; i++) vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; vsync_cfg.pp_count = sde_enc->num_phys_encs; vsync_cfg.frame_rate = mode_info.frame_rate; vsync_cfg.is_dummy = is_dummy; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); } } static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_display_info *disp_info, bool is_dummy) { struct sde_encoder_phys *phys; int i, rc = 0; u32 vsync_source; if (!sde_enc || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); return; } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d\n", sde_enc->num_phys_encs, (int) ARRAY_SIZE(sde_enc->hw_pp)); return; } if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { if (is_dummy) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; else if (disp_info->is_te_using_watchdog_timer) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; else vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO; vsync_cfg.is_dummy = is_dummy; vsync_source = SDE_VSYNC0_SOURCE_GPIO; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); for (i = 0; i < sde_enc->num_phys_encs; i++) { phys = sde_enc->phys_encs[i]; if (phys && phys->ops.setup_vsync_source) phys->ops.setup_vsync_source(phys, vsync_source, is_dummy); } } } Loading drivers/gpu/drm/msm/sde/sde_encoder_phys.h +15 −1 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -137,6 +137,7 @@ struct sde_encoder_virt_ops { * @wait_dma_trigger: Returns true if lut dma has to trigger and wait * unitl transaction is complete. * @wait_for_active: Wait for display scan line to be in active area * @setup_vsync_source: Configure vsync source selection for cmd mode. */ struct sde_encoder_phys_ops { Loading Loading @@ -186,6 +187,8 @@ struct sde_encoder_phys_ops { int (*get_wr_line_count)(struct sde_encoder_phys *phys); bool (*wait_dma_trigger)(struct sde_encoder_phys *phys); int (*wait_for_active)(struct sde_encoder_phys *phys); void (*setup_vsync_source)(struct sde_encoder_phys *phys, u32 vsync_source, bool is_dummy); }; /** Loading Loading @@ -265,6 +268,7 @@ struct sde_encoder_irq { * fences that have to be signalled. * @pending_kickoff_wq: Wait queue for blocking until kickoff completes * @irq: IRQ tracking structures * @has_intf_te: Interface TE configuration support */ struct sde_encoder_phys { struct drm_encoder *parent; Loading Loading @@ -295,6 +299,7 @@ struct sde_encoder_phys { atomic_t pending_retire_fence_cnt; wait_queue_head_t pending_kickoff_wq; struct sde_encoder_irq irq[INTR_IDX_MAX]; bool has_intf_te; }; static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) Loading Loading @@ -497,6 +502,15 @@ void sde_encoder_helper_trigger_flush(struct sde_encoder_phys *phys_enc); */ void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc); /** * sde_encoder_helper_vsync_config - configure vsync source for cmd mode * @phys_enc: Pointer to physical encoder structure * @vsync_source: vsync source selection * @is_dummy: used only for RSC */ void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source, bool is_dummy); /** * sde_encoder_helper_wait_event_timeout - wait for event with timeout * taking into account that jiffies may jump between reads leading to Loading drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +216 −69 Original line number Diff line number Diff line Loading @@ -93,10 +93,11 @@ static void _sde_encoder_phys_cmd_config_autorefresh( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; struct sde_hw_intf *hw_intf = phys_enc->hw_intf; struct drm_connector *conn = phys_enc->connector; struct sde_hw_autorefresh *cfg_cur, cfg_nxt; if (!conn || !conn->state || !hw_pp) if (!conn || !conn->state || !hw_pp || !hw_intf) return; cfg_cur = &cmd_enc->autorefresh.cfg; Loading @@ -108,15 +109,18 @@ static void _sde_encoder_phys_cmd_config_autorefresh( SDE_DEBUG_CMDENC(cmd_enc, "autorefresh state %d->%d framecount %d\n", cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); SDE_EVT32(DRMID(phys_enc->parent), hw_pp->idx, cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); SDE_EVT32(DRMID(phys_enc->parent), hw_pp->idx, hw_intf->idx, cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); /* only proceed on state changes */ if (cfg_nxt.enable == cfg_cur->enable) return; memcpy(cfg_cur, &cfg_nxt, sizeof(*cfg_cur)); if (hw_pp->ops.setup_autorefresh) if (phys_enc->has_intf_te && hw_intf->ops.setup_autorefresh) hw_intf->ops.setup_autorefresh(hw_intf, cfg_cur); else if (hw_pp->ops.setup_autorefresh) hw_pp->ops.setup_autorefresh(hw_pp, cfg_cur); } Loading Loading @@ -256,13 +260,13 @@ static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx) wake_up_all(&cmd_enc->autorefresh.kickoff_wq); } static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) { struct sde_encoder_phys *phys_enc = arg; struct sde_encoder_phys_cmd *cmd_enc; u32 event = 0; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return; SDE_ATRACE_BEGIN("rd_ptr_irq"); Loading @@ -284,7 +288,9 @@ static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) } SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, event, 0xfff); phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, event, 0xfff); if (phys_enc->parent_ops.handle_vblank_virt) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, Loading Loading @@ -370,6 +376,9 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( { struct sde_encoder_irq *irq; if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return; irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; irq->irq_idx = -EINVAL; Loading @@ -379,16 +388,22 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_RDPTR]; irq->hw_idx = phys_enc->hw_pp->idx; irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else irq->hw_idx = phys_enc->hw_pp->idx; irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; irq->hw_idx = phys_enc->intf_idx; irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; irq->hw_idx = phys_enc->hw_pp->idx; irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else irq->hw_idx = phys_enc->hw_pp->idx; } static void sde_encoder_phys_cmd_cont_splash_mode_set( Loading Loading @@ -535,36 +550,58 @@ static int _sde_encoder_phys_cmd_poll_write_pointer_started( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; struct sde_hw_intf *hw_intf = phys_enc->hw_intf; struct sde_hw_pp_vsync_info info; u32 timeout_us = SDE_ENC_WR_PTR_START_TIMEOUT_US; int ret; int ret = 0; if (!hw_pp || !hw_pp->ops.get_vsync_info || !hw_pp->ops.poll_timeout_wr_ptr) if (!hw_pp || !hw_intf) return 0; if (phys_enc->has_intf_te) { if (!hw_intf->ops.get_vsync_info || !hw_intf->ops.poll_timeout_wr_ptr) goto end; } else { if (!hw_pp->ops.get_vsync_info || !hw_pp->ops.poll_timeout_wr_ptr) goto end; } if (phys_enc->has_intf_te) ret = hw_intf->ops.get_vsync_info(hw_intf, &info); else ret = hw_pp->ops.get_vsync_info(hw_pp, &info); if (ret) return ret; SDE_DEBUG_CMDENC(cmd_enc, "pp:%d rd_ptr %d wr_ptr %d\n", "pp:%d intf:%d rd_ptr %d wr_ptr %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, info.rd_ptr_line_count, info.wr_ptr_line_count); SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, info.wr_ptr_line_count); if (phys_enc->has_intf_te) ret = hw_intf->ops.poll_timeout_wr_ptr(hw_intf, timeout_us); else ret = hw_pp->ops.poll_timeout_wr_ptr(hw_pp, timeout_us); if (ret) { SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, timeout_us, ret); SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic"); } end: return ret; } Loading @@ -573,18 +610,28 @@ static bool _sde_encoder_phys_cmd_is_ongoing_pptx( { struct sde_hw_pingpong *hw_pp; struct sde_hw_pp_vsync_info info; struct sde_hw_intf *hw_intf; if (!phys_enc) return false; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf || !hw_intf->ops.get_vsync_info) return false; hw_intf->ops.get_vsync_info(hw_intf, &info); } else { hw_pp = phys_enc->hw_pp; if (!hw_pp || !hw_pp->ops.get_vsync_info) return false; hw_pp->ops.get_vsync_info(hw_pp, &info); } SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, atomic_read(&phys_enc->pending_kickoff_cnt), info.wr_ptr_line_count, phys_enc->cached_mode.vdisplay); Loading Loading @@ -772,19 +819,29 @@ static void sde_encoder_phys_cmd_tearcheck_config( struct msm_drm_private *priv; struct sde_kms *sde_kms; if (!phys_enc || !phys_enc->hw_pp) { if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) { SDE_ERROR("invalid encoder\n"); return; } mode = &phys_enc->cached_mode; SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); SDE_DEBUG_CMDENC(cmd_enc, "pp %d, intf %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0); if (phys_enc->has_intf_te) { if (!phys_enc->hw_intf->ops.setup_tearcheck || !phys_enc->hw_intf->ops.enable_tearcheck) { SDE_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); return; } } else { if (!phys_enc->hw_pp->ops.setup_tearcheck || !phys_enc->hw_pp->ops.enable_tearcheck) { SDE_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); return; } } sde_kms = phys_enc->sde_kms; if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { Loading Loading @@ -828,24 +885,38 @@ static void sde_encoder_phys_cmd_tearcheck_config( tc_cfg.rd_ptr_irq = mode->vdisplay + 1; SDE_DEBUG_CMDENC(cmd_enc, "tc %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", phys_enc->hw_pp->idx - PINGPONG_0, vsync_hz, mode->vtotal, mode->vrefresh); "tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, vsync_hz, mode->vtotal, mode->vrefresh); SDE_DEBUG_CMDENC(cmd_enc, "tc %d enable %u start_pos %u rd_ptr_irq %u\n", phys_enc->hw_pp->idx - PINGPONG_0, tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq); "tc %d intf %d enable %u start_pos %u rd_ptr_irq %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq); SDE_DEBUG_CMDENC(cmd_enc, "tc %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.hw_vsync_mode, tc_cfg.vsync_count, tc_cfg.vsync_init_val); "tc %d intf %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_cfg.hw_vsync_mode, tc_cfg.vsync_count, tc_cfg.vsync_init_val); SDE_DEBUG_CMDENC(cmd_enc, "tc %d cfgheight %u thresh_start %u thresh_cont %u\n", phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.sync_cfg_height, "tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_cfg.sync_cfg_height, tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue); if (phys_enc->has_intf_te) { phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf, &tc_cfg); phys_enc->hw_intf->ops.enable_tearcheck(phys_enc->hw_intf, tc_enable); } else { phys_enc->hw_pp->ops.setup_tearcheck(phys_enc->hw_pp, &tc_cfg); phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable); phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable); } } static void _sde_encoder_phys_cmd_pingpong_config( Loading Loading @@ -920,20 +991,30 @@ static bool sde_encoder_phys_cmd_is_autorefresh_enabled( struct sde_encoder_phys *phys_enc) { struct sde_hw_pingpong *hw_pp; struct sde_hw_intf *hw_intf; struct sde_hw_autorefresh cfg; int ret; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return 0; if (!sde_encoder_phys_cmd_is_master(phys_enc)) return 0; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf->ops.get_autorefresh) return 0; ret = hw_intf->ops.get_autorefresh(hw_intf, &cfg); } else { hw_pp = phys_enc->hw_pp; if (!hw_pp->ops.get_autorefresh) return 0; ret = hw_pp->ops.get_autorefresh(hw_pp, &cfg); } if (ret) return 0; Loading @@ -943,50 +1024,78 @@ static bool sde_encoder_phys_cmd_is_autorefresh_enabled( static void sde_encoder_phys_cmd_connect_te( struct sde_encoder_phys *phys_enc, bool enable) { if (!phys_enc || !phys_enc->hw_pp || if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf || !phys_enc->hw_pp->ops.connect_external_te) return; SDE_EVT32(DRMID(phys_enc->parent), enable); phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable); if (phys_enc->has_intf_te) phys_enc->hw_intf->ops.connect_external_te(phys_enc->hw_intf, enable); else phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable); } static int sde_encoder_phys_cmd_get_line_count( static int sde_encoder_phys_cmd_te_get_line_count( struct sde_encoder_phys *phys_enc) { struct sde_hw_pingpong *hw_pp; struct sde_hw_intf *hw_intf; u32 line_count; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return -EINVAL; if (!sde_encoder_phys_cmd_is_master(phys_enc)) return -EINVAL; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf->ops.get_line_count) return -EINVAL; line_count = hw_intf->ops.get_line_count(hw_intf); } else { hw_pp = phys_enc->hw_pp; if (!hw_pp->ops.get_line_count) return -EINVAL; return hw_pp->ops.get_line_count(hw_pp); line_count = hw_pp->ops.get_line_count(hw_pp); } return line_count; } static int sde_encoder_phys_cmd_get_write_line_count( struct sde_encoder_phys *phys_enc) { struct sde_hw_pingpong *hw_pp; struct sde_hw_intf *hw_intf; struct sde_hw_pp_vsync_info info; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return -EINVAL; if (!sde_encoder_phys_cmd_is_master(phys_enc)) return -EINVAL; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf->ops.get_vsync_info) return -EINVAL; if (hw_intf->ops.get_vsync_info(hw_intf, &info)) return -EINVAL; } else { hw_pp = phys_enc->hw_pp; if (!hw_pp->ops.get_vsync_info) return -EINVAL; if (hw_pp->ops.get_vsync_info(hw_pp, &info)) return -EINVAL; } return (int)info.wr_ptr_line_count; } Loading @@ -996,14 +1105,16 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); if (!phys_enc || !phys_enc->hw_pp) { if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) { SDE_ERROR("invalid encoder\n"); return; } SDE_DEBUG_CMDENC(cmd_enc, "pp %d state %d\n", SDE_DEBUG_CMDENC(cmd_enc, "pp %d intf %d state %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, phys_enc->enable_state); SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, phys_enc->enable_state); if (phys_enc->enable_state == SDE_ENC_DISABLED) { Loading @@ -1011,8 +1122,14 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) return; } if (phys_enc->hw_pp->ops.enable_tearcheck) phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false); if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.enable_tearcheck) phys_enc->hw_intf->ops.enable_tearcheck( phys_enc->hw_intf, false); else if (phys_enc->hw_pp->ops.enable_tearcheck) phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false); phys_enc->enable_state = SDE_ENC_DISABLED; } Loading Loading @@ -1307,8 +1424,21 @@ static void sde_encoder_phys_cmd_trigger_start( } } static void sde_encoder_phys_cmd_init_ops( struct sde_encoder_phys_ops *ops) static void sde_encoder_phys_cmd_setup_vsync_source( struct sde_encoder_phys *phys_enc, u32 vsync_source, bool is_dummy) { if (!phys_enc || !phys_enc->hw_intf) return; sde_encoder_helper_vsync_config(phys_enc, vsync_source, is_dummy); if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, vsync_source); } static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops) { ops->prepare_commit = sde_encoder_phys_cmd_prepare_commit; ops->is_master = sde_encoder_phys_cmd_is_master; Loading @@ -1334,9 +1464,10 @@ static void sde_encoder_phys_cmd_init_ops( ops->control_te = sde_encoder_phys_cmd_connect_te; ops->is_autorefresh_enabled = sde_encoder_phys_cmd_is_autorefresh_enabled; ops->get_line_count = sde_encoder_phys_cmd_get_line_count; ops->get_line_count = sde_encoder_phys_cmd_te_get_line_count; ops->get_wr_line_count = sde_encoder_phys_cmd_get_write_line_count; ops->wait_for_active = NULL; ops->setup_vsync_source = sde_encoder_phys_cmd_setup_vsync_source; } struct sde_encoder_phys *sde_encoder_phys_cmd_init( Loading Loading @@ -1367,7 +1498,6 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->hw_mdptop = hw_mdp; phys_enc->intf_idx = p->intf_idx; sde_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->parent = p->parent; phys_enc->parent_ops = p->parent_ops; phys_enc->sde_kms = p->sde_kms; Loading @@ -1376,7 +1506,14 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->enc_spinlock = p->enc_spinlock; cmd_enc->stream_sel = 0; phys_enc->enable_state = SDE_ENC_DISABLED; sde_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->comp_type = p->comp_type; if (sde_hw_intf_te_supported(phys_enc->sde_kms->catalog)) phys_enc->has_intf_te = true; else phys_enc->has_intf_te = false; for (i = 0; i < INTR_IDX_MAX; i++) { irq = &phys_enc->irq[i]; INIT_LIST_HEAD(&irq->cb.list); Loading @@ -1398,10 +1535,15 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq->cb.func = sde_encoder_phys_cmd_pp_tx_done_irq; irq = &phys_enc->irq[INTR_IDX_RDPTR]; irq->name = "pp_rd_ptr"; irq->intr_type = SDE_IRQ_TYPE_PING_PONG_RD_PTR; irq->intr_idx = INTR_IDX_RDPTR; irq->cb.func = sde_encoder_phys_cmd_pp_rd_ptr_irq; irq->name = "te_rd_ptr"; if (phys_enc->has_intf_te) irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_RD_PTR; else irq->intr_type = SDE_IRQ_TYPE_PING_PONG_RD_PTR; irq->cb.func = sde_encoder_phys_cmd_te_rd_ptr_irq; irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; irq->name = "underrun"; Loading @@ -1411,7 +1553,12 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; irq->name = "autorefresh_done"; if (phys_enc->has_intf_te) irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF; else irq->intr_type = SDE_IRQ_TYPE_PING_PONG_AUTO_REF; irq->intr_idx = INTR_IDX_AUTOREFRESH_DONE; irq->cb.func = sde_encoder_phys_cmd_autorefresh_done_irq; Loading drivers/gpu/drm/msm/sde/sde_hw_catalog.c +4 −0 Original line number Diff line number Diff line Loading @@ -1748,6 +1748,10 @@ static int sde_intf_parse_dt(struct device_node *np, set_bit(SDE_INTF_ROT_START, &intf->features); if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) set_bit(SDE_INTF_INPUT_CTRL, &intf->features); if (IS_SDE_MAJOR_MINOR_SAME((sde_cfg->hwversion), SDE_HW_VER_500)) set_bit(SDE_INTF_TE, &intf->features); } end: Loading drivers/gpu/drm/msm/sde/sde_hw_catalog.h +5 −0 Original line number Diff line number Diff line Loading @@ -1147,4 +1147,9 @@ static inline bool sde_hw_sspp_multirect_enabled(const struct sde_sspp_cfg *cfg) return test_bit(SDE_SSPP_SMART_DMA_V1, &cfg->features) || test_bit(SDE_SSPP_SMART_DMA_V2, &cfg->features); } static inline sde_hw_intf_te_supported(const struct sde_mdss_cfg *sde_cfg) { return test_bit(SDE_INTF_TE, &(sde_cfg->intf[0].features)); } #endif /* _SDE_HW_CATALOG_H */ Loading
drivers/gpu/drm/msm/sde/sde_encoder.c +43 −12 Original line number Diff line number Diff line Loading @@ -1558,8 +1558,8 @@ static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc, return ret; } static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_display_info *disp_info, bool is_dummy) void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source, bool is_dummy) { struct sde_vsync_source_cfg vsync_cfg = { 0 }; struct msm_drm_private *priv; Loading @@ -1567,11 +1567,11 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct sde_hw_mdp *hw_mdptop; struct drm_encoder *drm_enc; struct msm_mode_info mode_info; struct sde_encoder_virt *sde_enc; int i, rc = 0; if (!sde_enc || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); if (!sde_enc) { SDE_ERROR("invalid param sde_enc:%d\n", sde_enc != NULL); return; } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d\n", Loading @@ -1580,6 +1580,8 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, return; } sde_enc = to_sde_encoder_virt(phys_enc->parent); drm_enc = &sde_enc->base; /* this pointers are checked in virt_enable_helper */ priv = drm_enc->dev->dev_private; Loading @@ -1602,22 +1604,51 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, return; } if (hw_mdptop->ops.setup_vsync_source && disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { if (hw_mdptop->ops.setup_vsync_source) { for (i = 0; i < sde_enc->num_phys_encs; i++) vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; vsync_cfg.pp_count = sde_enc->num_phys_encs; vsync_cfg.frame_rate = mode_info.frame_rate; vsync_cfg.is_dummy = is_dummy; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); } } static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_display_info *disp_info, bool is_dummy) { struct sde_encoder_phys *phys; int i, rc = 0; u32 vsync_source; if (!sde_enc || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); return; } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { SDE_ERROR("invalid num phys enc %d/%d\n", sde_enc->num_phys_encs, (int) ARRAY_SIZE(sde_enc->hw_pp)); return; } if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { if (is_dummy) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1; else if (disp_info->is_te_using_watchdog_timer) vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; else vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO; vsync_cfg.is_dummy = is_dummy; vsync_source = SDE_VSYNC0_SOURCE_GPIO; hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); for (i = 0; i < sde_enc->num_phys_encs; i++) { phys = sde_enc->phys_encs[i]; if (phys && phys->ops.setup_vsync_source) phys->ops.setup_vsync_source(phys, vsync_source, is_dummy); } } } Loading
drivers/gpu/drm/msm/sde/sde_encoder_phys.h +15 −1 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -137,6 +137,7 @@ struct sde_encoder_virt_ops { * @wait_dma_trigger: Returns true if lut dma has to trigger and wait * unitl transaction is complete. * @wait_for_active: Wait for display scan line to be in active area * @setup_vsync_source: Configure vsync source selection for cmd mode. */ struct sde_encoder_phys_ops { Loading Loading @@ -186,6 +187,8 @@ struct sde_encoder_phys_ops { int (*get_wr_line_count)(struct sde_encoder_phys *phys); bool (*wait_dma_trigger)(struct sde_encoder_phys *phys); int (*wait_for_active)(struct sde_encoder_phys *phys); void (*setup_vsync_source)(struct sde_encoder_phys *phys, u32 vsync_source, bool is_dummy); }; /** Loading Loading @@ -265,6 +268,7 @@ struct sde_encoder_irq { * fences that have to be signalled. * @pending_kickoff_wq: Wait queue for blocking until kickoff completes * @irq: IRQ tracking structures * @has_intf_te: Interface TE configuration support */ struct sde_encoder_phys { struct drm_encoder *parent; Loading Loading @@ -295,6 +299,7 @@ struct sde_encoder_phys { atomic_t pending_retire_fence_cnt; wait_queue_head_t pending_kickoff_wq; struct sde_encoder_irq irq[INTR_IDX_MAX]; bool has_intf_te; }; static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) Loading Loading @@ -497,6 +502,15 @@ void sde_encoder_helper_trigger_flush(struct sde_encoder_phys *phys_enc); */ void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc); /** * sde_encoder_helper_vsync_config - configure vsync source for cmd mode * @phys_enc: Pointer to physical encoder structure * @vsync_source: vsync source selection * @is_dummy: used only for RSC */ void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source, bool is_dummy); /** * sde_encoder_helper_wait_event_timeout - wait for event with timeout * taking into account that jiffies may jump between reads leading to Loading
drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +216 −69 Original line number Diff line number Diff line Loading @@ -93,10 +93,11 @@ static void _sde_encoder_phys_cmd_config_autorefresh( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; struct sde_hw_intf *hw_intf = phys_enc->hw_intf; struct drm_connector *conn = phys_enc->connector; struct sde_hw_autorefresh *cfg_cur, cfg_nxt; if (!conn || !conn->state || !hw_pp) if (!conn || !conn->state || !hw_pp || !hw_intf) return; cfg_cur = &cmd_enc->autorefresh.cfg; Loading @@ -108,15 +109,18 @@ static void _sde_encoder_phys_cmd_config_autorefresh( SDE_DEBUG_CMDENC(cmd_enc, "autorefresh state %d->%d framecount %d\n", cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); SDE_EVT32(DRMID(phys_enc->parent), hw_pp->idx, cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); SDE_EVT32(DRMID(phys_enc->parent), hw_pp->idx, hw_intf->idx, cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); /* only proceed on state changes */ if (cfg_nxt.enable == cfg_cur->enable) return; memcpy(cfg_cur, &cfg_nxt, sizeof(*cfg_cur)); if (hw_pp->ops.setup_autorefresh) if (phys_enc->has_intf_te && hw_intf->ops.setup_autorefresh) hw_intf->ops.setup_autorefresh(hw_intf, cfg_cur); else if (hw_pp->ops.setup_autorefresh) hw_pp->ops.setup_autorefresh(hw_pp, cfg_cur); } Loading Loading @@ -256,13 +260,13 @@ static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx) wake_up_all(&cmd_enc->autorefresh.kickoff_wq); } static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) { struct sde_encoder_phys *phys_enc = arg; struct sde_encoder_phys_cmd *cmd_enc; u32 event = 0; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return; SDE_ATRACE_BEGIN("rd_ptr_irq"); Loading @@ -284,7 +288,9 @@ static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) } SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, event, 0xfff); phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, event, 0xfff); if (phys_enc->parent_ops.handle_vblank_virt) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, Loading Loading @@ -370,6 +376,9 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( { struct sde_encoder_irq *irq; if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return; irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; irq->irq_idx = -EINVAL; Loading @@ -379,16 +388,22 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_RDPTR]; irq->hw_idx = phys_enc->hw_pp->idx; irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else irq->hw_idx = phys_enc->hw_pp->idx; irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; irq->hw_idx = phys_enc->intf_idx; irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; irq->hw_idx = phys_enc->hw_pp->idx; irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else irq->hw_idx = phys_enc->hw_pp->idx; } static void sde_encoder_phys_cmd_cont_splash_mode_set( Loading Loading @@ -535,36 +550,58 @@ static int _sde_encoder_phys_cmd_poll_write_pointer_started( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; struct sde_hw_intf *hw_intf = phys_enc->hw_intf; struct sde_hw_pp_vsync_info info; u32 timeout_us = SDE_ENC_WR_PTR_START_TIMEOUT_US; int ret; int ret = 0; if (!hw_pp || !hw_pp->ops.get_vsync_info || !hw_pp->ops.poll_timeout_wr_ptr) if (!hw_pp || !hw_intf) return 0; if (phys_enc->has_intf_te) { if (!hw_intf->ops.get_vsync_info || !hw_intf->ops.poll_timeout_wr_ptr) goto end; } else { if (!hw_pp->ops.get_vsync_info || !hw_pp->ops.poll_timeout_wr_ptr) goto end; } if (phys_enc->has_intf_te) ret = hw_intf->ops.get_vsync_info(hw_intf, &info); else ret = hw_pp->ops.get_vsync_info(hw_pp, &info); if (ret) return ret; SDE_DEBUG_CMDENC(cmd_enc, "pp:%d rd_ptr %d wr_ptr %d\n", "pp:%d intf:%d rd_ptr %d wr_ptr %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, info.rd_ptr_line_count, info.wr_ptr_line_count); SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, info.wr_ptr_line_count); if (phys_enc->has_intf_te) ret = hw_intf->ops.poll_timeout_wr_ptr(hw_intf, timeout_us); else ret = hw_pp->ops.poll_timeout_wr_ptr(hw_pp, timeout_us); if (ret) { SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, timeout_us, ret); SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic"); } end: return ret; } Loading @@ -573,18 +610,28 @@ static bool _sde_encoder_phys_cmd_is_ongoing_pptx( { struct sde_hw_pingpong *hw_pp; struct sde_hw_pp_vsync_info info; struct sde_hw_intf *hw_intf; if (!phys_enc) return false; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf || !hw_intf->ops.get_vsync_info) return false; hw_intf->ops.get_vsync_info(hw_intf, &info); } else { hw_pp = phys_enc->hw_pp; if (!hw_pp || !hw_pp->ops.get_vsync_info) return false; hw_pp->ops.get_vsync_info(hw_pp, &info); } SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, atomic_read(&phys_enc->pending_kickoff_cnt), info.wr_ptr_line_count, phys_enc->cached_mode.vdisplay); Loading Loading @@ -772,19 +819,29 @@ static void sde_encoder_phys_cmd_tearcheck_config( struct msm_drm_private *priv; struct sde_kms *sde_kms; if (!phys_enc || !phys_enc->hw_pp) { if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) { SDE_ERROR("invalid encoder\n"); return; } mode = &phys_enc->cached_mode; SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); SDE_DEBUG_CMDENC(cmd_enc, "pp %d, intf %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0); if (phys_enc->has_intf_te) { if (!phys_enc->hw_intf->ops.setup_tearcheck || !phys_enc->hw_intf->ops.enable_tearcheck) { SDE_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); return; } } else { if (!phys_enc->hw_pp->ops.setup_tearcheck || !phys_enc->hw_pp->ops.enable_tearcheck) { SDE_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); return; } } sde_kms = phys_enc->sde_kms; if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { Loading Loading @@ -828,24 +885,38 @@ static void sde_encoder_phys_cmd_tearcheck_config( tc_cfg.rd_ptr_irq = mode->vdisplay + 1; SDE_DEBUG_CMDENC(cmd_enc, "tc %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", phys_enc->hw_pp->idx - PINGPONG_0, vsync_hz, mode->vtotal, mode->vrefresh); "tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, vsync_hz, mode->vtotal, mode->vrefresh); SDE_DEBUG_CMDENC(cmd_enc, "tc %d enable %u start_pos %u rd_ptr_irq %u\n", phys_enc->hw_pp->idx - PINGPONG_0, tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq); "tc %d intf %d enable %u start_pos %u rd_ptr_irq %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq); SDE_DEBUG_CMDENC(cmd_enc, "tc %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.hw_vsync_mode, tc_cfg.vsync_count, tc_cfg.vsync_init_val); "tc %d intf %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_cfg.hw_vsync_mode, tc_cfg.vsync_count, tc_cfg.vsync_init_val); SDE_DEBUG_CMDENC(cmd_enc, "tc %d cfgheight %u thresh_start %u thresh_cont %u\n", phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.sync_cfg_height, "tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_cfg.sync_cfg_height, tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue); if (phys_enc->has_intf_te) { phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf, &tc_cfg); phys_enc->hw_intf->ops.enable_tearcheck(phys_enc->hw_intf, tc_enable); } else { phys_enc->hw_pp->ops.setup_tearcheck(phys_enc->hw_pp, &tc_cfg); phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable); phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable); } } static void _sde_encoder_phys_cmd_pingpong_config( Loading Loading @@ -920,20 +991,30 @@ static bool sde_encoder_phys_cmd_is_autorefresh_enabled( struct sde_encoder_phys *phys_enc) { struct sde_hw_pingpong *hw_pp; struct sde_hw_intf *hw_intf; struct sde_hw_autorefresh cfg; int ret; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return 0; if (!sde_encoder_phys_cmd_is_master(phys_enc)) return 0; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf->ops.get_autorefresh) return 0; ret = hw_intf->ops.get_autorefresh(hw_intf, &cfg); } else { hw_pp = phys_enc->hw_pp; if (!hw_pp->ops.get_autorefresh) return 0; ret = hw_pp->ops.get_autorefresh(hw_pp, &cfg); } if (ret) return 0; Loading @@ -943,50 +1024,78 @@ static bool sde_encoder_phys_cmd_is_autorefresh_enabled( static void sde_encoder_phys_cmd_connect_te( struct sde_encoder_phys *phys_enc, bool enable) { if (!phys_enc || !phys_enc->hw_pp || if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf || !phys_enc->hw_pp->ops.connect_external_te) return; SDE_EVT32(DRMID(phys_enc->parent), enable); phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable); if (phys_enc->has_intf_te) phys_enc->hw_intf->ops.connect_external_te(phys_enc->hw_intf, enable); else phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable); } static int sde_encoder_phys_cmd_get_line_count( static int sde_encoder_phys_cmd_te_get_line_count( struct sde_encoder_phys *phys_enc) { struct sde_hw_pingpong *hw_pp; struct sde_hw_intf *hw_intf; u32 line_count; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return -EINVAL; if (!sde_encoder_phys_cmd_is_master(phys_enc)) return -EINVAL; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf->ops.get_line_count) return -EINVAL; line_count = hw_intf->ops.get_line_count(hw_intf); } else { hw_pp = phys_enc->hw_pp; if (!hw_pp->ops.get_line_count) return -EINVAL; return hw_pp->ops.get_line_count(hw_pp); line_count = hw_pp->ops.get_line_count(hw_pp); } return line_count; } static int sde_encoder_phys_cmd_get_write_line_count( struct sde_encoder_phys *phys_enc) { struct sde_hw_pingpong *hw_pp; struct sde_hw_intf *hw_intf; struct sde_hw_pp_vsync_info info; if (!phys_enc || !phys_enc->hw_pp) if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return -EINVAL; if (!sde_encoder_phys_cmd_is_master(phys_enc)) return -EINVAL; if (phys_enc->has_intf_te) { hw_intf = phys_enc->hw_intf; if (!hw_intf->ops.get_vsync_info) return -EINVAL; if (hw_intf->ops.get_vsync_info(hw_intf, &info)) return -EINVAL; } else { hw_pp = phys_enc->hw_pp; if (!hw_pp->ops.get_vsync_info) return -EINVAL; if (hw_pp->ops.get_vsync_info(hw_pp, &info)) return -EINVAL; } return (int)info.wr_ptr_line_count; } Loading @@ -996,14 +1105,16 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); if (!phys_enc || !phys_enc->hw_pp) { if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) { SDE_ERROR("invalid encoder\n"); return; } SDE_DEBUG_CMDENC(cmd_enc, "pp %d state %d\n", SDE_DEBUG_CMDENC(cmd_enc, "pp %d intf %d state %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, phys_enc->enable_state); SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, phys_enc->enable_state); if (phys_enc->enable_state == SDE_ENC_DISABLED) { Loading @@ -1011,8 +1122,14 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) return; } if (phys_enc->hw_pp->ops.enable_tearcheck) phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false); if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.enable_tearcheck) phys_enc->hw_intf->ops.enable_tearcheck( phys_enc->hw_intf, false); else if (phys_enc->hw_pp->ops.enable_tearcheck) phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false); phys_enc->enable_state = SDE_ENC_DISABLED; } Loading Loading @@ -1307,8 +1424,21 @@ static void sde_encoder_phys_cmd_trigger_start( } } static void sde_encoder_phys_cmd_init_ops( struct sde_encoder_phys_ops *ops) static void sde_encoder_phys_cmd_setup_vsync_source( struct sde_encoder_phys *phys_enc, u32 vsync_source, bool is_dummy) { if (!phys_enc || !phys_enc->hw_intf) return; sde_encoder_helper_vsync_config(phys_enc, vsync_source, is_dummy); if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, vsync_source); } static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops) { ops->prepare_commit = sde_encoder_phys_cmd_prepare_commit; ops->is_master = sde_encoder_phys_cmd_is_master; Loading @@ -1334,9 +1464,10 @@ static void sde_encoder_phys_cmd_init_ops( ops->control_te = sde_encoder_phys_cmd_connect_te; ops->is_autorefresh_enabled = sde_encoder_phys_cmd_is_autorefresh_enabled; ops->get_line_count = sde_encoder_phys_cmd_get_line_count; ops->get_line_count = sde_encoder_phys_cmd_te_get_line_count; ops->get_wr_line_count = sde_encoder_phys_cmd_get_write_line_count; ops->wait_for_active = NULL; ops->setup_vsync_source = sde_encoder_phys_cmd_setup_vsync_source; } struct sde_encoder_phys *sde_encoder_phys_cmd_init( Loading Loading @@ -1367,7 +1498,6 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->hw_mdptop = hw_mdp; phys_enc->intf_idx = p->intf_idx; sde_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->parent = p->parent; phys_enc->parent_ops = p->parent_ops; phys_enc->sde_kms = p->sde_kms; Loading @@ -1376,7 +1506,14 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->enc_spinlock = p->enc_spinlock; cmd_enc->stream_sel = 0; phys_enc->enable_state = SDE_ENC_DISABLED; sde_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->comp_type = p->comp_type; if (sde_hw_intf_te_supported(phys_enc->sde_kms->catalog)) phys_enc->has_intf_te = true; else phys_enc->has_intf_te = false; for (i = 0; i < INTR_IDX_MAX; i++) { irq = &phys_enc->irq[i]; INIT_LIST_HEAD(&irq->cb.list); Loading @@ -1398,10 +1535,15 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq->cb.func = sde_encoder_phys_cmd_pp_tx_done_irq; irq = &phys_enc->irq[INTR_IDX_RDPTR]; irq->name = "pp_rd_ptr"; irq->intr_type = SDE_IRQ_TYPE_PING_PONG_RD_PTR; irq->intr_idx = INTR_IDX_RDPTR; irq->cb.func = sde_encoder_phys_cmd_pp_rd_ptr_irq; irq->name = "te_rd_ptr"; if (phys_enc->has_intf_te) irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_RD_PTR; else irq->intr_type = SDE_IRQ_TYPE_PING_PONG_RD_PTR; irq->cb.func = sde_encoder_phys_cmd_te_rd_ptr_irq; irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; irq->name = "underrun"; Loading @@ -1411,7 +1553,12 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; irq->name = "autorefresh_done"; if (phys_enc->has_intf_te) irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF; else irq->intr_type = SDE_IRQ_TYPE_PING_PONG_AUTO_REF; irq->intr_idx = INTR_IDX_AUTOREFRESH_DONE; irq->cb.func = sde_encoder_phys_cmd_autorefresh_done_irq; Loading
drivers/gpu/drm/msm/sde/sde_hw_catalog.c +4 −0 Original line number Diff line number Diff line Loading @@ -1748,6 +1748,10 @@ static int sde_intf_parse_dt(struct device_node *np, set_bit(SDE_INTF_ROT_START, &intf->features); if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) set_bit(SDE_INTF_INPUT_CTRL, &intf->features); if (IS_SDE_MAJOR_MINOR_SAME((sde_cfg->hwversion), SDE_HW_VER_500)) set_bit(SDE_INTF_TE, &intf->features); } end: Loading
drivers/gpu/drm/msm/sde/sde_hw_catalog.h +5 −0 Original line number Diff line number Diff line Loading @@ -1147,4 +1147,9 @@ static inline bool sde_hw_sspp_multirect_enabled(const struct sde_sspp_cfg *cfg) return test_bit(SDE_SSPP_SMART_DMA_V1, &cfg->features) || test_bit(SDE_SSPP_SMART_DMA_V2, &cfg->features); } static inline sde_hw_intf_te_supported(const struct sde_mdss_cfg *sde_cfg) { return test_bit(SDE_INTF_TE, &(sde_cfg->intf[0].features)); } #endif /* _SDE_HW_CATALOG_H */