cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dpu_encoder_phys_cmd.c (23181B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights reserved.
      4 */
      5
      6#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
      7#include <linux/delay.h>
      8#include "dpu_encoder_phys.h"
      9#include "dpu_hw_interrupts.h"
     10#include "dpu_hw_pingpong.h"
     11#include "dpu_core_irq.h"
     12#include "dpu_formats.h"
     13#include "dpu_trace.h"
     14#include "disp/msm_disp_snapshot.h"
     15
     16#define DPU_DEBUG_CMDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \
     17		(e) && (e)->base.parent ? \
     18		(e)->base.parent->base.id : -1, \
     19		(e) ? (e)->base.intf_idx - INTF_0 : -1, ##__VA_ARGS__)
     20
     21#define DPU_ERROR_CMDENC(e, fmt, ...) DPU_ERROR("enc%d intf%d " fmt, \
     22		(e) && (e)->base.parent ? \
     23		(e)->base.parent->base.id : -1, \
     24		(e) ? (e)->base.intf_idx - INTF_0 : -1, ##__VA_ARGS__)
     25
     26#define to_dpu_encoder_phys_cmd(x) \
     27	container_of(x, struct dpu_encoder_phys_cmd, base)
     28
     29#define PP_TIMEOUT_MAX_TRIALS	10
     30
     31/*
     32 * Tearcheck sync start and continue thresholds are empirically found
     33 * based on common panels In the future, may want to allow panels to override
     34 * these default values
     35 */
     36#define DEFAULT_TEARCHECK_SYNC_THRESH_START	4
     37#define DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE	4
     38
     39#define DPU_ENC_WR_PTR_START_TIMEOUT_US 20000
     40
     41#define DPU_ENC_MAX_POLL_TIMEOUT_US	2000
     42
     43static bool dpu_encoder_phys_cmd_is_master(struct dpu_encoder_phys *phys_enc)
     44{
     45	return (phys_enc->split_role != ENC_ROLE_SLAVE);
     46}
     47
     48static void _dpu_encoder_phys_cmd_update_intf_cfg(
     49		struct dpu_encoder_phys *phys_enc)
     50{
     51	struct dpu_encoder_phys_cmd *cmd_enc =
     52			to_dpu_encoder_phys_cmd(phys_enc);
     53	struct dpu_hw_ctl *ctl;
     54	struct dpu_hw_intf_cfg intf_cfg = { 0 };
     55
     56	ctl = phys_enc->hw_ctl;
     57	if (!ctl->ops.setup_intf_cfg)
     58		return;
     59
     60	intf_cfg.intf = phys_enc->intf_idx;
     61	intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD;
     62	intf_cfg.stream_sel = cmd_enc->stream_sel;
     63	intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
     64	ctl->ops.setup_intf_cfg(ctl, &intf_cfg);
     65
     66	/* setup which pp blk will connect to this intf */
     67	if (test_bit(DPU_CTL_ACTIVE_CFG, &ctl->caps->features) && phys_enc->hw_intf->ops.bind_pingpong_blk)
     68		phys_enc->hw_intf->ops.bind_pingpong_blk(
     69				phys_enc->hw_intf,
     70				true,
     71				phys_enc->hw_pp->idx);
     72}
     73
     74static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
     75{
     76	struct dpu_encoder_phys *phys_enc = arg;
     77	unsigned long lock_flags;
     78	int new_cnt;
     79	u32 event = DPU_ENCODER_FRAME_EVENT_DONE;
     80
     81	if (!phys_enc->hw_pp)
     82		return;
     83
     84	DPU_ATRACE_BEGIN("pp_done_irq");
     85	/* notify all synchronous clients first, then asynchronous clients */
     86	if (phys_enc->parent_ops->handle_frame_done)
     87		phys_enc->parent_ops->handle_frame_done(phys_enc->parent,
     88				phys_enc, event);
     89
     90	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
     91	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
     92	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
     93
     94	trace_dpu_enc_phys_cmd_pp_tx_done(DRMID(phys_enc->parent),
     95					  phys_enc->hw_pp->idx - PINGPONG_0,
     96					  new_cnt, event);
     97
     98	/* Signal any waiting atomic commit thread */
     99	wake_up_all(&phys_enc->pending_kickoff_wq);
    100	DPU_ATRACE_END("pp_done_irq");
    101}
    102
    103static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
    104{
    105	struct dpu_encoder_phys *phys_enc = arg;
    106	struct dpu_encoder_phys_cmd *cmd_enc;
    107
    108	if (!phys_enc->hw_pp)
    109		return;
    110
    111	DPU_ATRACE_BEGIN("rd_ptr_irq");
    112	cmd_enc = to_dpu_encoder_phys_cmd(phys_enc);
    113
    114	if (phys_enc->parent_ops->handle_vblank_virt)
    115		phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
    116			phys_enc);
    117
    118	atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0);
    119	wake_up_all(&cmd_enc->pending_vblank_wq);
    120	DPU_ATRACE_END("rd_ptr_irq");
    121}
    122
    123static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)
    124{
    125	struct dpu_encoder_phys *phys_enc = arg;
    126
    127	DPU_ATRACE_BEGIN("ctl_start_irq");
    128
    129	atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
    130
    131	/* Signal any waiting ctl start interrupt */
    132	wake_up_all(&phys_enc->pending_kickoff_wq);
    133	DPU_ATRACE_END("ctl_start_irq");
    134}
    135
    136static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx)
    137{
    138	struct dpu_encoder_phys *phys_enc = arg;
    139
    140	if (phys_enc->parent_ops->handle_underrun_virt)
    141		phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent,
    142			phys_enc);
    143}
    144
    145static void dpu_encoder_phys_cmd_atomic_mode_set(
    146		struct dpu_encoder_phys *phys_enc,
    147		struct drm_crtc_state *crtc_state,
    148		struct drm_connector_state *conn_state)
    149{
    150	phys_enc->irq[INTR_IDX_CTL_START] = phys_enc->hw_ctl->caps->intr_start;
    151
    152	phys_enc->irq[INTR_IDX_PINGPONG] = phys_enc->hw_pp->caps->intr_done;
    153
    154	phys_enc->irq[INTR_IDX_RDPTR] = phys_enc->hw_pp->caps->intr_rdptr;
    155
    156	phys_enc->irq[INTR_IDX_UNDERRUN] = phys_enc->hw_intf->cap->intr_underrun;
    157}
    158
    159static int _dpu_encoder_phys_cmd_handle_ppdone_timeout(
    160		struct dpu_encoder_phys *phys_enc)
    161{
    162	struct dpu_encoder_phys_cmd *cmd_enc =
    163			to_dpu_encoder_phys_cmd(phys_enc);
    164	u32 frame_event = DPU_ENCODER_FRAME_EVENT_ERROR;
    165	bool do_log = false;
    166	struct drm_encoder *drm_enc;
    167
    168	if (!phys_enc->hw_pp)
    169		return -EINVAL;
    170
    171	drm_enc = phys_enc->parent;
    172
    173	cmd_enc->pp_timeout_report_cnt++;
    174	if (cmd_enc->pp_timeout_report_cnt == PP_TIMEOUT_MAX_TRIALS) {
    175		frame_event |= DPU_ENCODER_FRAME_EVENT_PANEL_DEAD;
    176		do_log = true;
    177	} else if (cmd_enc->pp_timeout_report_cnt == 1) {
    178		do_log = true;
    179	}
    180
    181	trace_dpu_enc_phys_cmd_pdone_timeout(DRMID(drm_enc),
    182		     phys_enc->hw_pp->idx - PINGPONG_0,
    183		     cmd_enc->pp_timeout_report_cnt,
    184		     atomic_read(&phys_enc->pending_kickoff_cnt),
    185		     frame_event);
    186
    187	/* to avoid flooding, only log first time, and "dead" time */
    188	if (do_log) {
    189		DRM_ERROR("id:%d pp:%d kickoff timeout %d cnt %d koff_cnt %d\n",
    190			  DRMID(drm_enc),
    191			  phys_enc->hw_pp->idx - PINGPONG_0,
    192			  phys_enc->hw_ctl->idx - CTL_0,
    193			  cmd_enc->pp_timeout_report_cnt,
    194			  atomic_read(&phys_enc->pending_kickoff_cnt));
    195		msm_disp_snapshot_state(drm_enc->dev);
    196		dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
    197				phys_enc->irq[INTR_IDX_RDPTR]);
    198	}
    199
    200	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
    201
    202	/* request a ctl reset before the next kickoff */
    203	phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET;
    204
    205	if (phys_enc->parent_ops->handle_frame_done)
    206		phys_enc->parent_ops->handle_frame_done(
    207				drm_enc, phys_enc, frame_event);
    208
    209	return -ETIMEDOUT;
    210}
    211
    212static int _dpu_encoder_phys_cmd_wait_for_idle(
    213		struct dpu_encoder_phys *phys_enc)
    214{
    215	struct dpu_encoder_phys_cmd *cmd_enc =
    216			to_dpu_encoder_phys_cmd(phys_enc);
    217	struct dpu_encoder_wait_info wait_info;
    218	int ret;
    219
    220	wait_info.wq = &phys_enc->pending_kickoff_wq;
    221	wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
    222	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
    223
    224	ret = dpu_encoder_helper_wait_for_irq(phys_enc,
    225			phys_enc->irq[INTR_IDX_PINGPONG],
    226			dpu_encoder_phys_cmd_pp_tx_done_irq,
    227			&wait_info);
    228	if (ret == -ETIMEDOUT)
    229		_dpu_encoder_phys_cmd_handle_ppdone_timeout(phys_enc);
    230	else if (!ret)
    231		cmd_enc->pp_timeout_report_cnt = 0;
    232
    233	return ret;
    234}
    235
    236static int dpu_encoder_phys_cmd_control_vblank_irq(
    237		struct dpu_encoder_phys *phys_enc,
    238		bool enable)
    239{
    240	int ret = 0;
    241	int refcount;
    242
    243	if (!phys_enc->hw_pp) {
    244		DPU_ERROR("invalid encoder\n");
    245		return -EINVAL;
    246	}
    247
    248	refcount = atomic_read(&phys_enc->vblank_refcount);
    249
    250	/* Slave encoders don't report vblank */
    251	if (!dpu_encoder_phys_cmd_is_master(phys_enc))
    252		goto end;
    253
    254	/* protect against negative */
    255	if (!enable && refcount == 0) {
    256		ret = -EINVAL;
    257		goto end;
    258	}
    259
    260	DRM_DEBUG_KMS("id:%u pp:%d enable=%s/%d\n", DRMID(phys_enc->parent),
    261		      phys_enc->hw_pp->idx - PINGPONG_0,
    262		      enable ? "true" : "false", refcount);
    263
    264	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
    265		ret = dpu_core_irq_register_callback(phys_enc->dpu_kms,
    266				phys_enc->irq[INTR_IDX_RDPTR],
    267				dpu_encoder_phys_cmd_pp_rd_ptr_irq,
    268				phys_enc);
    269	else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
    270		ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
    271				phys_enc->irq[INTR_IDX_RDPTR]);
    272
    273end:
    274	if (ret) {
    275		DRM_ERROR("vblank irq err id:%u pp:%d ret:%d, enable %s/%d\n",
    276			  DRMID(phys_enc->parent),
    277			  phys_enc->hw_pp->idx - PINGPONG_0, ret,
    278			  enable ? "true" : "false", refcount);
    279	}
    280
    281	return ret;
    282}
    283
    284static void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc,
    285		bool enable)
    286{
    287	trace_dpu_enc_phys_cmd_irq_ctrl(DRMID(phys_enc->parent),
    288			phys_enc->hw_pp->idx - PINGPONG_0,
    289			enable, atomic_read(&phys_enc->vblank_refcount));
    290
    291	if (enable) {
    292		dpu_core_irq_register_callback(phys_enc->dpu_kms,
    293				phys_enc->irq[INTR_IDX_PINGPONG],
    294				dpu_encoder_phys_cmd_pp_tx_done_irq,
    295				phys_enc);
    296		dpu_core_irq_register_callback(phys_enc->dpu_kms,
    297				phys_enc->irq[INTR_IDX_UNDERRUN],
    298				dpu_encoder_phys_cmd_underrun_irq,
    299				phys_enc);
    300		dpu_encoder_phys_cmd_control_vblank_irq(phys_enc, true);
    301
    302		if (dpu_encoder_phys_cmd_is_master(phys_enc))
    303			dpu_core_irq_register_callback(phys_enc->dpu_kms,
    304					phys_enc->irq[INTR_IDX_CTL_START],
    305					dpu_encoder_phys_cmd_ctl_start_irq,
    306					phys_enc);
    307	} else {
    308		if (dpu_encoder_phys_cmd_is_master(phys_enc))
    309			dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
    310					phys_enc->irq[INTR_IDX_CTL_START]);
    311
    312		dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
    313				phys_enc->irq[INTR_IDX_UNDERRUN]);
    314		dpu_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
    315		dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
    316				phys_enc->irq[INTR_IDX_PINGPONG]);
    317	}
    318}
    319
    320static void dpu_encoder_phys_cmd_tearcheck_config(
    321		struct dpu_encoder_phys *phys_enc)
    322{
    323	struct dpu_encoder_phys_cmd *cmd_enc =
    324		to_dpu_encoder_phys_cmd(phys_enc);
    325	struct dpu_hw_tear_check tc_cfg = { 0 };
    326	struct drm_display_mode *mode;
    327	bool tc_enable = true;
    328	u32 vsync_hz;
    329	struct dpu_kms *dpu_kms;
    330
    331	if (!phys_enc->hw_pp) {
    332		DPU_ERROR("invalid encoder\n");
    333		return;
    334	}
    335	mode = &phys_enc->cached_mode;
    336
    337	DPU_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
    338
    339	if (!phys_enc->hw_pp->ops.setup_tearcheck ||
    340		!phys_enc->hw_pp->ops.enable_tearcheck) {
    341		DPU_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n");
    342		return;
    343	}
    344
    345	dpu_kms = phys_enc->dpu_kms;
    346
    347	/*
    348	 * TE default: dsi byte clock calculated base on 70 fps;
    349	 * around 14 ms to complete a kickoff cycle if te disabled;
    350	 * vclk_line base on 60 fps; write is faster than read;
    351	 * init == start == rdptr;
    352	 *
    353	 * vsync_count is ratio of MDP VSYNC clock frequency to LCD panel
    354	 * frequency divided by the no. of rows (lines) in the LCDpanel.
    355	 */
    356	vsync_hz = dpu_kms_get_clk_rate(dpu_kms, "vsync");
    357	if (vsync_hz <= 0) {
    358		DPU_DEBUG_CMDENC(cmd_enc, "invalid - vsync_hz %u\n",
    359				 vsync_hz);
    360		return;
    361	}
    362
    363	tc_cfg.vsync_count = vsync_hz /
    364				(mode->vtotal * drm_mode_vrefresh(mode));
    365
    366	/*
    367	 * Set the sync_cfg_height to twice vtotal so that if we lose a
    368	 * TE event coming from the display TE pin we won't stall immediately
    369	 */
    370	tc_cfg.hw_vsync_mode = 1;
    371	tc_cfg.sync_cfg_height = mode->vtotal * 2;
    372	tc_cfg.vsync_init_val = mode->vdisplay;
    373	tc_cfg.sync_threshold_start = DEFAULT_TEARCHECK_SYNC_THRESH_START;
    374	tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE;
    375	tc_cfg.start_pos = mode->vdisplay;
    376	tc_cfg.rd_ptr_irq = mode->vdisplay + 1;
    377
    378	DPU_DEBUG_CMDENC(cmd_enc,
    379		"tc %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n",
    380		phys_enc->hw_pp->idx - PINGPONG_0, vsync_hz,
    381		mode->vtotal, drm_mode_vrefresh(mode));
    382	DPU_DEBUG_CMDENC(cmd_enc,
    383		"tc %d enable %u start_pos %u rd_ptr_irq %u\n",
    384		phys_enc->hw_pp->idx - PINGPONG_0, tc_enable, tc_cfg.start_pos,
    385		tc_cfg.rd_ptr_irq);
    386	DPU_DEBUG_CMDENC(cmd_enc,
    387		"tc %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n",
    388		phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.hw_vsync_mode,
    389		tc_cfg.vsync_count, tc_cfg.vsync_init_val);
    390	DPU_DEBUG_CMDENC(cmd_enc,
    391		"tc %d cfgheight %u thresh_start %u thresh_cont %u\n",
    392		phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.sync_cfg_height,
    393		tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue);
    394
    395	phys_enc->hw_pp->ops.setup_tearcheck(phys_enc->hw_pp, &tc_cfg);
    396	phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable);
    397}
    398
    399static void _dpu_encoder_phys_cmd_pingpong_config(
    400		struct dpu_encoder_phys *phys_enc)
    401{
    402	struct dpu_encoder_phys_cmd *cmd_enc =
    403		to_dpu_encoder_phys_cmd(phys_enc);
    404
    405	if (!phys_enc->hw_pp || !phys_enc->hw_ctl->ops.setup_intf_cfg) {
    406		DPU_ERROR("invalid arg(s), enc %d\n", phys_enc != NULL);
    407		return;
    408	}
    409
    410	DPU_DEBUG_CMDENC(cmd_enc, "pp %d, enabling mode:\n",
    411			phys_enc->hw_pp->idx - PINGPONG_0);
    412	drm_mode_debug_printmodeline(&phys_enc->cached_mode);
    413
    414	_dpu_encoder_phys_cmd_update_intf_cfg(phys_enc);
    415	dpu_encoder_phys_cmd_tearcheck_config(phys_enc);
    416}
    417
    418static bool dpu_encoder_phys_cmd_needs_single_flush(
    419		struct dpu_encoder_phys *phys_enc)
    420{
    421	/**
    422	 * we do separate flush for each CTL and let
    423	 * CTL_START synchronize them
    424	 */
    425	return false;
    426}
    427
    428static void dpu_encoder_phys_cmd_enable_helper(
    429		struct dpu_encoder_phys *phys_enc)
    430{
    431	struct dpu_hw_ctl *ctl;
    432
    433	if (!phys_enc->hw_pp) {
    434		DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != NULL);
    435		return;
    436	}
    437
    438	dpu_encoder_helper_split_config(phys_enc, phys_enc->intf_idx);
    439
    440	_dpu_encoder_phys_cmd_pingpong_config(phys_enc);
    441
    442	if (!dpu_encoder_phys_cmd_is_master(phys_enc))
    443		return;
    444
    445	ctl = phys_enc->hw_ctl;
    446	ctl->ops.update_pending_flush_intf(ctl, phys_enc->intf_idx);
    447}
    448
    449static void dpu_encoder_phys_cmd_enable(struct dpu_encoder_phys *phys_enc)
    450{
    451	struct dpu_encoder_phys_cmd *cmd_enc =
    452		to_dpu_encoder_phys_cmd(phys_enc);
    453
    454	if (!phys_enc->hw_pp) {
    455		DPU_ERROR("invalid phys encoder\n");
    456		return;
    457	}
    458
    459	DPU_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
    460
    461	if (phys_enc->enable_state == DPU_ENC_ENABLED) {
    462		DPU_ERROR("already enabled\n");
    463		return;
    464	}
    465
    466	dpu_encoder_phys_cmd_enable_helper(phys_enc);
    467	phys_enc->enable_state = DPU_ENC_ENABLED;
    468}
    469
    470static void _dpu_encoder_phys_cmd_connect_te(
    471		struct dpu_encoder_phys *phys_enc, bool enable)
    472{
    473	if (!phys_enc->hw_pp || !phys_enc->hw_pp->ops.connect_external_te)
    474		return;
    475
    476	trace_dpu_enc_phys_cmd_connect_te(DRMID(phys_enc->parent), enable);
    477	phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable);
    478}
    479
    480static void dpu_encoder_phys_cmd_prepare_idle_pc(
    481		struct dpu_encoder_phys *phys_enc)
    482{
    483	_dpu_encoder_phys_cmd_connect_te(phys_enc, false);
    484}
    485
    486static int dpu_encoder_phys_cmd_get_line_count(
    487		struct dpu_encoder_phys *phys_enc)
    488{
    489	struct dpu_hw_pingpong *hw_pp;
    490
    491	if (!phys_enc->hw_pp)
    492		return -EINVAL;
    493
    494	if (!dpu_encoder_phys_cmd_is_master(phys_enc))
    495		return -EINVAL;
    496
    497	hw_pp = phys_enc->hw_pp;
    498	if (!hw_pp->ops.get_line_count)
    499		return -EINVAL;
    500
    501	return hw_pp->ops.get_line_count(hw_pp);
    502}
    503
    504static void dpu_encoder_phys_cmd_disable(struct dpu_encoder_phys *phys_enc)
    505{
    506	struct dpu_encoder_phys_cmd *cmd_enc =
    507		to_dpu_encoder_phys_cmd(phys_enc);
    508	struct dpu_hw_ctl *ctl;
    509
    510	if (!phys_enc->hw_pp) {
    511		DPU_ERROR("invalid encoder\n");
    512		return;
    513	}
    514	DRM_DEBUG_KMS("id:%u pp:%d state:%d\n", DRMID(phys_enc->parent),
    515		      phys_enc->hw_pp->idx - PINGPONG_0,
    516		      phys_enc->enable_state);
    517
    518	if (phys_enc->enable_state == DPU_ENC_DISABLED) {
    519		DPU_ERROR_CMDENC(cmd_enc, "already disabled\n");
    520		return;
    521	}
    522
    523	if (phys_enc->hw_pp->ops.enable_tearcheck)
    524		phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false);
    525
    526	if (phys_enc->hw_intf->ops.bind_pingpong_blk) {
    527		phys_enc->hw_intf->ops.bind_pingpong_blk(
    528				phys_enc->hw_intf,
    529				false,
    530				phys_enc->hw_pp->idx);
    531
    532		ctl = phys_enc->hw_ctl;
    533		ctl->ops.update_pending_flush_intf(ctl, phys_enc->intf_idx);
    534	}
    535
    536	phys_enc->enable_state = DPU_ENC_DISABLED;
    537}
    538
    539static void dpu_encoder_phys_cmd_destroy(struct dpu_encoder_phys *phys_enc)
    540{
    541	struct dpu_encoder_phys_cmd *cmd_enc =
    542		to_dpu_encoder_phys_cmd(phys_enc);
    543
    544	kfree(cmd_enc);
    545}
    546
    547static void dpu_encoder_phys_cmd_prepare_for_kickoff(
    548		struct dpu_encoder_phys *phys_enc)
    549{
    550	struct dpu_encoder_phys_cmd *cmd_enc =
    551			to_dpu_encoder_phys_cmd(phys_enc);
    552	int ret;
    553
    554	if (!phys_enc->hw_pp) {
    555		DPU_ERROR("invalid encoder\n");
    556		return;
    557	}
    558	DRM_DEBUG_KMS("id:%u pp:%d pending_cnt:%d\n", DRMID(phys_enc->parent),
    559		      phys_enc->hw_pp->idx - PINGPONG_0,
    560		      atomic_read(&phys_enc->pending_kickoff_cnt));
    561
    562	/*
    563	 * Mark kickoff request as outstanding. If there are more than one,
    564	 * outstanding, then we have to wait for the previous one to complete
    565	 */
    566	ret = _dpu_encoder_phys_cmd_wait_for_idle(phys_enc);
    567	if (ret) {
    568		/* force pending_kickoff_cnt 0 to discard failed kickoff */
    569		atomic_set(&phys_enc->pending_kickoff_cnt, 0);
    570		DRM_ERROR("failed wait_for_idle: id:%u ret:%d pp:%d\n",
    571			  DRMID(phys_enc->parent), ret,
    572			  phys_enc->hw_pp->idx - PINGPONG_0);
    573	}
    574
    575	DPU_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n",
    576			phys_enc->hw_pp->idx - PINGPONG_0,
    577			atomic_read(&phys_enc->pending_kickoff_cnt));
    578}
    579
    580static bool dpu_encoder_phys_cmd_is_ongoing_pptx(
    581		struct dpu_encoder_phys *phys_enc)
    582{
    583	struct dpu_hw_pp_vsync_info info;
    584
    585	if (!phys_enc)
    586		return false;
    587
    588	phys_enc->hw_pp->ops.get_vsync_info(phys_enc->hw_pp, &info);
    589	if (info.wr_ptr_line_count > 0 &&
    590	    info.wr_ptr_line_count < phys_enc->cached_mode.vdisplay)
    591		return true;
    592
    593	return false;
    594}
    595
    596static void dpu_encoder_phys_cmd_prepare_commit(
    597		struct dpu_encoder_phys *phys_enc)
    598{
    599	struct dpu_encoder_phys_cmd *cmd_enc =
    600		to_dpu_encoder_phys_cmd(phys_enc);
    601	int trial = 0;
    602
    603	if (!phys_enc)
    604		return;
    605	if (!phys_enc->hw_pp)
    606		return;
    607	if (!dpu_encoder_phys_cmd_is_master(phys_enc))
    608		return;
    609
    610	/* If autorefresh is already disabled, we have nothing to do */
    611	if (!phys_enc->hw_pp->ops.get_autorefresh(phys_enc->hw_pp, NULL))
    612		return;
    613
    614	/*
    615	 * If autorefresh is enabled, disable it and make sure it is safe to
    616	 * proceed with current frame commit/push. Sequence fallowed is,
    617	 * 1. Disable TE
    618	 * 2. Disable autorefresh config
    619	 * 4. Poll for frame transfer ongoing to be false
    620	 * 5. Enable TE back
    621	 */
    622	_dpu_encoder_phys_cmd_connect_te(phys_enc, false);
    623	phys_enc->hw_pp->ops.setup_autorefresh(phys_enc->hw_pp, 0, false);
    624
    625	do {
    626		udelay(DPU_ENC_MAX_POLL_TIMEOUT_US);
    627		if ((trial * DPU_ENC_MAX_POLL_TIMEOUT_US)
    628				> (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) {
    629			DPU_ERROR_CMDENC(cmd_enc,
    630					"disable autorefresh failed\n");
    631			break;
    632		}
    633
    634		trial++;
    635	} while (dpu_encoder_phys_cmd_is_ongoing_pptx(phys_enc));
    636
    637	_dpu_encoder_phys_cmd_connect_te(phys_enc, true);
    638
    639	DPU_DEBUG_CMDENC(to_dpu_encoder_phys_cmd(phys_enc),
    640			 "disabled autorefresh\n");
    641}
    642
    643static int _dpu_encoder_phys_cmd_wait_for_ctl_start(
    644		struct dpu_encoder_phys *phys_enc)
    645{
    646	struct dpu_encoder_phys_cmd *cmd_enc =
    647			to_dpu_encoder_phys_cmd(phys_enc);
    648	struct dpu_encoder_wait_info wait_info;
    649	int ret;
    650
    651	wait_info.wq = &phys_enc->pending_kickoff_wq;
    652	wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt;
    653	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
    654
    655	ret = dpu_encoder_helper_wait_for_irq(phys_enc,
    656			phys_enc->irq[INTR_IDX_CTL_START],
    657			dpu_encoder_phys_cmd_ctl_start_irq,
    658			&wait_info);
    659	if (ret == -ETIMEDOUT) {
    660		DPU_ERROR_CMDENC(cmd_enc, "ctl start interrupt wait failed\n");
    661		ret = -EINVAL;
    662	} else if (!ret)
    663		ret = 0;
    664
    665	return ret;
    666}
    667
    668static int dpu_encoder_phys_cmd_wait_for_tx_complete(
    669		struct dpu_encoder_phys *phys_enc)
    670{
    671	int rc;
    672
    673	rc = _dpu_encoder_phys_cmd_wait_for_idle(phys_enc);
    674	if (rc) {
    675		DRM_ERROR("failed wait_for_idle: id:%u ret:%d intf:%d\n",
    676			  DRMID(phys_enc->parent), rc,
    677			  phys_enc->intf_idx - INTF_0);
    678	}
    679
    680	return rc;
    681}
    682
    683static int dpu_encoder_phys_cmd_wait_for_commit_done(
    684		struct dpu_encoder_phys *phys_enc)
    685{
    686	/* only required for master controller */
    687	if (!dpu_encoder_phys_cmd_is_master(phys_enc))
    688		return 0;
    689
    690	if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl))
    691		return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc);
    692
    693	return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc);
    694}
    695
    696static int dpu_encoder_phys_cmd_wait_for_vblank(
    697		struct dpu_encoder_phys *phys_enc)
    698{
    699	int rc = 0;
    700	struct dpu_encoder_phys_cmd *cmd_enc;
    701	struct dpu_encoder_wait_info wait_info;
    702
    703	cmd_enc = to_dpu_encoder_phys_cmd(phys_enc);
    704
    705	/* only required for master controller */
    706	if (!dpu_encoder_phys_cmd_is_master(phys_enc))
    707		return rc;
    708
    709	wait_info.wq = &cmd_enc->pending_vblank_wq;
    710	wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt;
    711	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
    712
    713	atomic_inc(&cmd_enc->pending_vblank_cnt);
    714
    715	rc = dpu_encoder_helper_wait_for_irq(phys_enc,
    716			phys_enc->irq[INTR_IDX_RDPTR],
    717			dpu_encoder_phys_cmd_pp_rd_ptr_irq,
    718			&wait_info);
    719
    720	return rc;
    721}
    722
    723static void dpu_encoder_phys_cmd_handle_post_kickoff(
    724		struct dpu_encoder_phys *phys_enc)
    725{
    726	/**
    727	 * re-enable external TE, either for the first time after enabling
    728	 * or if disabled for Autorefresh
    729	 */
    730	_dpu_encoder_phys_cmd_connect_te(phys_enc, true);
    731}
    732
    733static void dpu_encoder_phys_cmd_trigger_start(
    734		struct dpu_encoder_phys *phys_enc)
    735{
    736	dpu_encoder_helper_trigger_start(phys_enc);
    737}
    738
    739static void dpu_encoder_phys_cmd_init_ops(
    740		struct dpu_encoder_phys_ops *ops)
    741{
    742	ops->prepare_commit = dpu_encoder_phys_cmd_prepare_commit;
    743	ops->is_master = dpu_encoder_phys_cmd_is_master;
    744	ops->atomic_mode_set = dpu_encoder_phys_cmd_atomic_mode_set;
    745	ops->enable = dpu_encoder_phys_cmd_enable;
    746	ops->disable = dpu_encoder_phys_cmd_disable;
    747	ops->destroy = dpu_encoder_phys_cmd_destroy;
    748	ops->control_vblank_irq = dpu_encoder_phys_cmd_control_vblank_irq;
    749	ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done;
    750	ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff;
    751	ops->wait_for_tx_complete = dpu_encoder_phys_cmd_wait_for_tx_complete;
    752	ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank;
    753	ops->trigger_start = dpu_encoder_phys_cmd_trigger_start;
    754	ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush;
    755	ops->irq_control = dpu_encoder_phys_cmd_irq_control;
    756	ops->restore = dpu_encoder_phys_cmd_enable_helper;
    757	ops->prepare_idle_pc = dpu_encoder_phys_cmd_prepare_idle_pc;
    758	ops->handle_post_kickoff = dpu_encoder_phys_cmd_handle_post_kickoff;
    759	ops->get_line_count = dpu_encoder_phys_cmd_get_line_count;
    760}
    761
    762struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
    763		struct dpu_enc_phys_init_params *p)
    764{
    765	struct dpu_encoder_phys *phys_enc = NULL;
    766	struct dpu_encoder_phys_cmd *cmd_enc = NULL;
    767	int i, ret = 0;
    768
    769	DPU_DEBUG("intf %d\n", p->intf_idx - INTF_0);
    770
    771	cmd_enc = kzalloc(sizeof(*cmd_enc), GFP_KERNEL);
    772	if (!cmd_enc) {
    773		ret = -ENOMEM;
    774		DPU_ERROR("failed to allocate\n");
    775		return ERR_PTR(ret);
    776	}
    777	phys_enc = &cmd_enc->base;
    778	phys_enc->hw_mdptop = p->dpu_kms->hw_mdp;
    779	phys_enc->intf_idx = p->intf_idx;
    780
    781	dpu_encoder_phys_cmd_init_ops(&phys_enc->ops);
    782	phys_enc->parent = p->parent;
    783	phys_enc->parent_ops = p->parent_ops;
    784	phys_enc->dpu_kms = p->dpu_kms;
    785	phys_enc->split_role = p->split_role;
    786	phys_enc->intf_mode = INTF_MODE_CMD;
    787	phys_enc->enc_spinlock = p->enc_spinlock;
    788	cmd_enc->stream_sel = 0;
    789	phys_enc->enable_state = DPU_ENC_DISABLED;
    790	for (i = 0; i < ARRAY_SIZE(phys_enc->irq); i++)
    791		phys_enc->irq[i] = -EINVAL;
    792
    793	atomic_set(&phys_enc->vblank_refcount, 0);
    794	atomic_set(&phys_enc->pending_kickoff_cnt, 0);
    795	atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
    796	atomic_set(&cmd_enc->pending_vblank_cnt, 0);
    797	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
    798	init_waitqueue_head(&cmd_enc->pending_vblank_wq);
    799
    800	DPU_DEBUG_CMDENC(cmd_enc, "created\n");
    801
    802	return phys_enc;
    803}