From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 946 +++++++++++++++++++++++----------------------------------- 1 files changed, 373 insertions(+), 573 deletions(-) diff --git a/kernel/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/kernel/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 19e2753..408fc6c 100644 --- a/kernel/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/kernel/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1,34 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ -#include <linux/kthread.h> #include <linux/debugfs.h> +#include <linux/kthread.h> #include <linux/seq_file.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_file.h> +#include <drm/drm_probe_helper.h> #include "msm_drv.h" #include "dpu_kms.h" -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_intf.h" #include "dpu_hw_ctl.h" +#include "dpu_hw_dspp.h" #include "dpu_formats.h" #include "dpu_encoder_phys.h" #include "dpu_crtc.h" @@ -65,11 +57,12 @@ #define MAX_CHANNELS_PER_ENC 2 -#define MISR_BUFF_SIZE 256 - #define IDLE_SHORT_TIMEOUT 1 -#define MAX_VDISPLAY_SPLIT 1080 +#define MAX_HDISPLAY_SPLIT 1080 + +/* timeout in frames waiting for frame done */ +#define DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES 5 /** * enum dpu_enc_rc_events - events for resource control state machine @@ -132,8 +125,9 @@ * Virtual encoder defers as much as possible to the physical encoders. * Virtual encoder registers itself with the DRM Framework as the encoder. * @base: drm_encoder base class for registration with DRM - * @enc_spin_lock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @bus_scaling_client: Client handle to the bus scaling interface + * @enabled: True if the encoder is active, protected by enc_lock * @num_phys_encs: Actual number of physical encoders contained. * @phys_encs: Container of physical encoders managed. * @cur_master: Pointer to the current master in this mode. Optimization @@ -143,26 +137,26 @@ * @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 - * @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 + * @crtc: Pointer to the currently assigned crtc. Normally you + * would use crtc->state->encoder_mask to determine the + * link between encoder/crtc. However in this case we need + * to track crtc in the disable() hook which is called + * _after_ encoder_mask is cleared. * @crtc_kickoff_cb: Callback into CRTC that will flush & start * all CTL paths * @crtc_kickoff_cb_data: Opaque user data given to crtc_kickoff_cb * @debugfs_root: Debug file system root file node - * @enc_lock: Lock around physical encoder create/destroy and - access. + * @enc_lock: Lock around physical encoder + * create/destroy/enable/disable * @frame_busy_mask: Bitmask tracking which phys_enc we are still * busy processing current command. * Bit0 = phys_encs[0] etc. * @crtc_frame_event_cb: callback handler for frame event * @crtc_frame_event_cb_data: callback handler private data - * @frame_done_timeout: frame done timeout in Hz + * @frame_done_timeout_ms: frame done timeout in ms * @frame_done_timer: watchdog timer for frame done event * @vsync_event_timer: vsync timer * @disp_info: local copy of msm_display_info struct - * @misr_enable: misr enable/disable status - * @misr_frame_count: misr frame count before start capturing the data * @idle_pc_supported: indicate if idle power collaps is supported * @rc_lock: resource control mutex lock to protect * virt encoder over various state changes @@ -171,7 +165,6 @@ * clks and resources after IDLE_TIMEOUT time. * @vsync_event_work: worker to handle vsync event for autorefresh * @topology: topology of the display - * @mode_set_complete: flag to indicate modeset completion * @idle_timeout: idle timeout duration in milliseconds */ struct dpu_encoder_virt { @@ -179,17 +172,17 @@ spinlock_t enc_spinlock; uint32_t bus_scaling_client; - uint32_t display_num_of_h_tiles; + bool enabled; unsigned int num_phys_encs; struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; struct dpu_encoder_phys *cur_master; + struct dpu_encoder_phys *cur_slave; struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; bool intfs_swapped; - void (*crtc_vblank_cb)(void *); - void *crtc_vblank_cb_data; + struct drm_crtc *crtc; struct dentry *debugfs_root; struct mutex enc_lock; @@ -197,58 +190,52 @@ void (*crtc_frame_event_cb)(void *, u32 event); void *crtc_frame_event_cb_data; - atomic_t frame_done_timeout; + atomic_t frame_done_timeout_ms; struct timer_list frame_done_timer; struct timer_list vsync_event_timer; struct msm_display_info disp_info; - bool misr_enable; - u32 misr_frame_count; bool idle_pc_supported; struct mutex rc_lock; enum dpu_enc_rc_states rc_state; - struct kthread_delayed_work delayed_off_work; + struct delayed_work delayed_off_work; struct kthread_work vsync_event_work; struct msm_display_topology topology; - bool mode_set_complete; u32 idle_timeout; }; #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base) -static inline int _dpu_encoder_power_enable(struct dpu_encoder_virt *dpu_enc, - bool enable) + +static u32 dither_matrix[DITHER_MATRIX_SZ] = { + 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10 +}; + +static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bpc) { - struct drm_encoder *drm_enc; - struct msm_drm_private *priv; - struct dpu_kms *dpu_kms; + struct dpu_hw_dither_cfg dither_cfg = { 0 }; - if (!dpu_enc) { - DPU_ERROR("invalid dpu enc\n"); - return -EINVAL; + if (!hw_pp->ops.setup_dither) + return; + + switch (bpc) { + case 6: + dither_cfg.c0_bitdepth = 6; + dither_cfg.c1_bitdepth = 6; + dither_cfg.c2_bitdepth = 6; + dither_cfg.c3_bitdepth = 6; + dither_cfg.temporal_en = 0; + break; + default: + hw_pp->ops.setup_dither(hw_pp, NULL); + return; } - drm_enc = &dpu_enc->base; - if (!drm_enc->dev || !drm_enc->dev->dev_private) { - DPU_ERROR("drm device invalid\n"); - return -EINVAL; - } + memcpy(&dither_cfg.matrix, dither_matrix, + sizeof(u32) * DITHER_MATRIX_SZ); - priv = drm_enc->dev->dev_private; - if (!priv->kms) { - DPU_ERROR("invalid kms\n"); - return -EINVAL; - } - - dpu_kms = to_dpu_kms(priv->kms); - - if (enable) - pm_runtime_get_sync(&dpu_kms->pdev->dev); - else - pm_runtime_put_sync(&dpu_kms->pdev->dev); - - return 0; + hw_pp->ops.setup_dither(hw_pp, &dither_cfg); } void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, @@ -275,7 +262,7 @@ u32 irq_status; int ret; - if (!phys_enc || !wait_info || intr_idx >= INTR_IDX_MAX) { + if (!wait_info || intr_idx >= INTR_IDX_MAX) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -350,7 +337,7 @@ struct dpu_encoder_irq *irq; int ret = 0; - if (!phys_enc || intr_idx >= INTR_IDX_MAX) { + if (intr_idx >= INTR_IDX_MAX) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -405,10 +392,6 @@ struct dpu_encoder_irq *irq; int ret; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return -EINVAL; - } irq = &phys_enc->irq[intr_idx]; /* silently skip irqs that weren't registered */ @@ -443,30 +426,22 @@ } void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, - struct dpu_encoder_hw_resources *hw_res, - struct drm_connector_state *conn_state) + struct dpu_encoder_hw_resources *hw_res) { struct dpu_encoder_virt *dpu_enc = NULL; int i = 0; - - if (!hw_res || !drm_enc || !conn_state) { - DPU_ERROR("invalid argument(s), drm_enc %d, res %d, state %d\n", - drm_enc != 0, hw_res != 0, conn_state != 0); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); DPU_DEBUG_ENC(dpu_enc, "\n"); /* Query resources used by phys encs, expected to be without overlap */ memset(hw_res, 0, sizeof(*hw_res)); - hw_res->display_num_of_h_tiles = dpu_enc->display_num_of_h_tiles; for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.get_hw_resources) - phys->ops.get_hw_resources(phys, hw_res, conn_state); + if (phys->ops.get_hw_resources) + phys->ops.get_hw_resources(phys, hw_res); } } @@ -488,7 +463,7 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.destroy) { + if (phys->ops.destroy) { phys->ops.destroy(phys); --dpu_enc->num_phys_encs; dpu_enc->phys_encs[i] = NULL; @@ -514,8 +489,8 @@ struct dpu_hw_mdp *hw_mdptop; struct msm_display_info *disp_info; - if (!phys_enc || !phys_enc->hw_mdptop || !phys_enc->parent) { - DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0); + if (!phys_enc->hw_mdptop || !phys_enc->parent) { + DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != NULL); return; } @@ -523,7 +498,7 @@ hw_mdptop = phys_enc->hw_mdptop; disp_info = &dpu_enc->disp_info; - if (disp_info->intf_type != DRM_MODE_CONNECTOR_DSI) + if (disp_info->intf_type != DRM_MODE_ENCODER_DSI) return; /** @@ -554,38 +529,43 @@ } } -static void _dpu_encoder_adjust_mode(struct drm_connector *connector, - struct drm_display_mode *adj_mode) -{ - struct drm_display_mode *cur_mode; - - if (!connector || !adj_mode) - return; - - list_for_each_entry(cur_mode, &connector->modes, head) { - if (cur_mode->vdisplay == adj_mode->vdisplay && - cur_mode->hdisplay == adj_mode->hdisplay && - cur_mode->vrefresh == adj_mode->vrefresh) { - adj_mode->private = cur_mode->private; - adj_mode->private_flags |= cur_mode->private_flags; - } - } -} - static struct msm_display_topology dpu_encoder_get_topology( struct dpu_encoder_virt *dpu_enc, struct dpu_kms *dpu_kms, struct drm_display_mode *mode) { - struct msm_display_topology topology; + struct msm_display_topology topology = {0}; int i, intf_count = 0; for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) if (dpu_enc->phys_encs[i]) intf_count++; - /* User split topology for width > 1080 */ - topology.num_lm = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; + /* Datapath topology selection + * + * Dual display + * 2 LM, 2 INTF ( Split display using 2 interfaces) + * + * Single display + * 1 LM, 1 INTF + * 2 LM, 1 INTF (stream merge to support high resolution interfaces) + * + * Adding color blocks only to primary interface if available in + * sufficient number + */ + if (intf_count == 2) + topology.num_lm = 2; + else if (!dpu_kms->catalog->caps->has_3d_merge) + topology.num_lm = 1; + else + topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; + + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) { + if (dpu_kms->catalog->dspp && + (dpu_kms->catalog->dspp_count >= topology.num_lm)) + topology.num_dspp = topology.num_lm; + } + topology.num_enc = 0; topology.num_intf = intf_count; @@ -602,12 +582,13 @@ const struct drm_display_mode *mode; struct drm_display_mode *adj_mode; struct msm_display_topology topology; + struct dpu_global_state *global_state; int i = 0; int ret = 0; if (!drm_enc || !crtc_state || !conn_state) { DPU_ERROR("invalid arg(s), drm_enc %d, crtc/conn state %d/%d\n", - drm_enc != 0, crtc_state != 0, conn_state != 0); + drm_enc != NULL, crtc_state != NULL, conn_state != NULL); return -EINVAL; } @@ -618,25 +599,20 @@ dpu_kms = to_dpu_kms(priv->kms); mode = &crtc_state->mode; adj_mode = &crtc_state->adjusted_mode; - trace_dpu_enc_atomic_check(DRMID(drm_enc)); + global_state = dpu_kms_get_global_state(crtc_state->state); + if (IS_ERR(global_state)) + return PTR_ERR(global_state); - /* - * display drivers may populate private fields of the drm display mode - * structure while registering possible modes of a connector with DRM. - * These private fields are not populated back while DRM invokes - * the mode_set callbacks. This module retrieves and populates the - * private fields of the given mode. - */ - _dpu_encoder_adjust_mode(conn_state->connector, adj_mode); + trace_dpu_enc_atomic_check(DRMID(drm_enc)); /* perform atomic check on the first physical encoder (master) */ for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.atomic_check) + if (phys->ops.atomic_check) ret = phys->ops.atomic_check(phys, crtc_state, conn_state); - else if (phys && phys->ops.mode_fixup) + else if (phys->ops.mode_fixup) if (!phys->ops.mode_fixup(phys, mode, adj_mode)) ret = -EINVAL; @@ -649,25 +625,22 @@ topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); - /* Reserve dynamic resources now. Indicating AtomicTest phase */ + /* Reserve dynamic resources now. */ if (!ret) { /* - * Avoid reserving resources when mode set is pending. Topology - * info may not be available to complete reservation. + * Release and Allocate resources on every modeset + * Dont allocate when active is false. */ - if (drm_atomic_crtc_needs_modeset(crtc_state) - && dpu_enc->mode_set_complete) { - ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, crtc_state, - conn_state, topology, true); - dpu_enc->mode_set_complete = false; + if (drm_atomic_crtc_needs_modeset(crtc_state)) { + dpu_rm_release(global_state, drm_enc); + + if (!crtc_state->active_changed || crtc_state->enable) + ret = dpu_rm_reserve(&dpu_kms->rm, global_state, + drm_enc, crtc_state, topology); } } - if (!ret) - drm_mode_set_crtcinfo(adj_mode, 0); - - trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags, - adj_mode->private_flags); + trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags); return ret; } @@ -698,11 +671,6 @@ priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); - if (!dpu_kms) { - DPU_ERROR("invalid dpu_kms\n"); - return; - } - hw_mdptop = dpu_kms->hw_mdp; if (!hw_mdptop) { DPU_ERROR("invalid mdptop\n"); @@ -740,7 +708,7 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.irq_control) + if (phys->ops.irq_control) phys->ops.irq_control(phys, enable); } @@ -786,11 +754,9 @@ { struct dpu_encoder_virt *dpu_enc; struct msm_drm_private *priv; - struct msm_drm_thread *disp_thread; bool is_vid_mode = false; - if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || - !drm_enc->crtc) { + if (!drm_enc || !drm_enc->dev || !drm_enc->crtc) { DPU_ERROR("invalid parameters\n"); return -EINVAL; } @@ -798,12 +764,6 @@ priv = drm_enc->dev->dev_private; is_vid_mode = dpu_enc->disp_info.capabilities & MSM_DISPLAY_CAP_VID_MODE; - - if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { - DPU_ERROR("invalid crtc index\n"); - return -EINVAL; - } - disp_thread = &priv->disp_thread[drm_enc->crtc->index]; /* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET @@ -821,8 +781,7 @@ switch (sw_event) { case DPU_ENC_RC_EVENT_KICKOFF: /* cancel delayed off work, if any */ - if (kthread_cancel_delayed_work_sync( - &dpu_enc->delayed_off_work)) + if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work)) DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", sw_event); @@ -881,10 +840,8 @@ return 0; } - kthread_queue_delayed_work( - &disp_thread->worker, - &dpu_enc->delayed_off_work, - msecs_to_jiffies(dpu_enc->idle_timeout)); + queue_delayed_work(priv->wq, &dpu_enc->delayed_off_work, + msecs_to_jiffies(dpu_enc->idle_timeout)); trace_dpu_enc_rc(DRMID(drm_enc), sw_event, dpu_enc->idle_pc_supported, dpu_enc->rc_state, @@ -893,8 +850,7 @@ case DPU_ENC_RC_EVENT_PRE_STOP: /* cancel delayed off work, if any */ - if (kthread_cancel_delayed_work_sync( - &dpu_enc->delayed_off_work)) + if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work)) DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", sw_event); @@ -1014,10 +970,16 @@ struct dpu_kms *dpu_kms; struct list_head *connector_list; struct drm_connector *conn = NULL, *conn_iter; - struct dpu_rm_hw_iter pp_iter; + struct drm_crtc *drm_crtc; + struct dpu_crtc_state *cstate; + struct dpu_global_state *global_state; struct msm_display_topology topology; - enum dpu_rm_topology_name topology_name; - int i = 0, ret; + struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL }; + int num_lm, num_ctl, num_pp, num_dspp; + int i, j; if (!drm_enc) { DPU_ERROR("invalid encoder\n"); @@ -1031,7 +993,16 @@ dpu_kms = to_dpu_kms(priv->kms); connector_list = &dpu_kms->dev->mode_config.connector_list; + global_state = dpu_kms_get_existing_global_state(dpu_kms); + if (IS_ERR_OR_NULL(global_state)) { + DPU_ERROR("Failed to get global state"); + return; + } + trace_dpu_enc_mode_set(DRMID(drm_enc)); + + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) + msm_dp_display_mode_set(priv->dp, drm_enc, mode, adj_mode); list_for_each_entry(conn_iter, connector_list, head) if (conn_iter->encoder == drm_enc) @@ -1045,63 +1016,95 @@ return; } + drm_for_each_crtc(drm_crtc, drm_enc->dev) + if (drm_crtc->state->encoder_mask & drm_encoder_mask(drm_enc)) + break; + topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); - /* Reserve dynamic resources now. Indicating non-AtomicTest phase */ - ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, drm_enc->crtc->state, - conn->state, topology, false); - if (ret) { - DPU_ERROR_ENC(dpu_enc, - "failed to reserve hw resources, %d\n", ret); - return; + /* Query resource that have been reserved in atomic check step. */ + num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_PINGPONG, hw_pp, + ARRAY_SIZE(hw_pp)); + num_ctl = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl)); + num_lm = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_LM, hw_lm, ARRAY_SIZE(hw_lm)); + num_dspp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp, + ARRAY_SIZE(hw_dspp)); + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) + dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i]) + : NULL; + + cstate = to_dpu_crtc_state(drm_crtc->state); + + for (i = 0; i < num_lm; i++) { + int ctl_idx = (i < num_ctl) ? i : (num_ctl-1); + + cstate->mixers[i].hw_lm = to_dpu_hw_mixer(hw_lm[i]); + cstate->mixers[i].lm_ctl = to_dpu_hw_ctl(hw_ctl[ctl_idx]); + cstate->mixers[i].hw_dspp = to_dpu_hw_dspp(hw_dspp[i]); } - dpu_rm_init_hw_iter(&pp_iter, drm_enc->base.id, DPU_HW_BLK_PINGPONG); - for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { - dpu_enc->hw_pp[i] = NULL; - if (!dpu_rm_get_hw(&dpu_kms->rm, &pp_iter)) - break; - dpu_enc->hw_pp[i] = (struct dpu_hw_pingpong *) pp_iter.hw; - } + cstate->num_mixers = num_lm; - topology_name = dpu_rm_get_topology_name(topology); for (i = 0; i < dpu_enc->num_phys_encs; i++) { + int num_blk; + struct dpu_hw_blk *hw_blk[MAX_CHANNELS_PER_ENC]; struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys) { - if (!dpu_enc->hw_pp[i]) { - DPU_ERROR_ENC(dpu_enc, - "invalid pingpong block for the encoder\n"); - return; - } - phys->hw_pp = dpu_enc->hw_pp[i]; - phys->connector = conn->state->connector; - phys->topology_name = topology_name; - if (phys->ops.mode_set) - phys->ops.mode_set(phys, mode, adj_mode); + if (!dpu_enc->hw_pp[i]) { + DPU_ERROR_ENC(dpu_enc, + "no pp block assigned at idx: %d\n", i); + return; } - } - dpu_enc->mode_set_complete = true; + if (!hw_ctl[i]) { + DPU_ERROR_ENC(dpu_enc, + "no ctl block assigned at idx: %d\n", i); + return; + } + + phys->hw_pp = dpu_enc->hw_pp[i]; + phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]); + + num_blk = dpu_rm_get_assigned_resources(&dpu_kms->rm, + global_state, drm_enc->base.id, DPU_HW_BLK_INTF, + hw_blk, ARRAY_SIZE(hw_blk)); + for (j = 0; j < num_blk; j++) { + struct dpu_hw_intf *hw_intf; + + hw_intf = to_dpu_hw_intf(hw_blk[i]); + if (hw_intf->idx == phys->intf_idx) + phys->hw_intf = hw_intf; + } + + if (!phys->hw_intf) { + DPU_ERROR_ENC(dpu_enc, + "no intf block assigned at idx: %d\n", i); + return; + } + + phys->connector = conn->state->connector; + if (phys->ops.mode_set) + phys->ops.mode_set(phys, mode, adj_mode); + } } static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = NULL; struct msm_drm_private *priv; - struct dpu_kms *dpu_kms; + int i; - if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + if (!drm_enc || !drm_enc->dev) { DPU_ERROR("invalid parameters\n"); return; } priv = drm_enc->dev->dev_private; - dpu_kms = to_dpu_kms(priv->kms); - if (!dpu_kms) { - DPU_ERROR("invalid dpu_kms\n"); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); if (!dpu_enc || !dpu_enc->cur_master) { @@ -1109,49 +1112,51 @@ return; } - if (dpu_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort && - dpu_enc->cur_master->hw_mdptop && - dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select) - dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select( - dpu_enc->cur_master->hw_mdptop); - if (dpu_enc->cur_master->hw_mdptop && - dpu_enc->cur_master->hw_mdptop->ops.reset_ubwc) - dpu_enc->cur_master->hw_mdptop->ops.reset_ubwc( - dpu_enc->cur_master->hw_mdptop, - dpu_kms->catalog); + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS && + dpu_enc->cur_master->hw_mdptop && + dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select) + dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select( + dpu_enc->cur_master->hw_mdptop); _dpu_encoder_update_vsync_source(dpu_enc, &dpu_enc->disp_info); + + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI && + !WARN_ON(dpu_enc->num_phys_encs == 0)) { + unsigned bpc = dpu_enc->phys_encs[0]->connector->display_info.bpc; + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + if (!dpu_enc->hw_pp[i]) + continue; + _dpu_encoder_setup_dither(dpu_enc->hw_pp[i], bpc); + } + } } -void dpu_encoder_virt_restore(struct drm_encoder *drm_enc) +void dpu_encoder_virt_runtime_resume(struct drm_encoder *drm_enc) { - struct dpu_encoder_virt *dpu_enc = NULL; - int i; + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - dpu_enc = to_dpu_encoder_virt(drm_enc); + mutex_lock(&dpu_enc->enc_lock); - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + if (!dpu_enc->enabled) + goto out; - if (phys && (phys != dpu_enc->cur_master) && phys->ops.restore) - phys->ops.restore(phys); - } - + if (dpu_enc->cur_slave && dpu_enc->cur_slave->ops.restore) + dpu_enc->cur_slave->ops.restore(dpu_enc->cur_slave); if (dpu_enc->cur_master && dpu_enc->cur_master->ops.restore) dpu_enc->cur_master->ops.restore(dpu_enc->cur_master); _dpu_encoder_virt_enable_helper(drm_enc); + +out: + mutex_unlock(&dpu_enc->enc_lock); } static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = NULL; - int i, ret = 0; + int ret = 0; + struct msm_drm_private *priv; struct drm_display_mode *cur_mode = NULL; if (!drm_enc) { @@ -1159,55 +1164,43 @@ return; } dpu_enc = to_dpu_encoder_virt(drm_enc); + + mutex_lock(&dpu_enc->enc_lock); cur_mode = &dpu_enc->base.crtc->state->adjusted_mode; + priv = drm_enc->dev->dev_private; trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay, cur_mode->vdisplay); - dpu_enc->cur_master = NULL; - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + /* always enable slave encoder before master */ + if (dpu_enc->cur_slave && dpu_enc->cur_slave->ops.enable) + dpu_enc->cur_slave->ops.enable(dpu_enc->cur_slave); - if (phys && phys->ops.is_master && phys->ops.is_master(phys)) { - DPU_DEBUG_ENC(dpu_enc, "master is now idx %d\n", i); - dpu_enc->cur_master = phys; - break; - } - } - - if (!dpu_enc->cur_master) { - DPU_ERROR("virt encoder has no master! num_phys %d\n", i); - return; - } + if (dpu_enc->cur_master && dpu_enc->cur_master->ops.enable) + dpu_enc->cur_master->ops.enable(dpu_enc->cur_master); ret = dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_KICKOFF); if (ret) { DPU_ERROR_ENC(dpu_enc, "dpu resource control failed: %d\n", ret); - return; + goto out; } - - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (!phys) - continue; - - if (phys != dpu_enc->cur_master) { - if (phys->ops.enable) - phys->ops.enable(phys); - } - - if (dpu_enc->misr_enable && (dpu_enc->disp_info.capabilities & - MSM_DISPLAY_CAP_VID_MODE) && phys->ops.setup_misr) - phys->ops.setup_misr(phys, true, - dpu_enc->misr_frame_count); - } - - if (dpu_enc->cur_master->ops.enable) - dpu_enc->cur_master->ops.enable(dpu_enc->cur_master); _dpu_encoder_virt_enable_helper(drm_enc); + + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) { + ret = msm_dp_display_enable(priv->dp, + drm_enc); + if (ret) { + DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n", + ret); + goto out; + } + } + dpu_enc->enabled = true; + +out: + mutex_unlock(&dpu_enc->enc_lock); } static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) @@ -1215,7 +1208,6 @@ struct dpu_encoder_virt *dpu_enc = NULL; struct msm_drm_private *priv; struct dpu_kms *dpu_kms; - struct drm_display_mode *mode; int i = 0; if (!drm_enc) { @@ -1224,15 +1216,13 @@ } else if (!drm_enc->dev) { DPU_ERROR("invalid dev\n"); return; - } else if (!drm_enc->dev->dev_private) { - DPU_ERROR("invalid dev_private\n"); - return; } - - mode = &drm_enc->crtc->state->adjusted_mode; dpu_enc = to_dpu_encoder_virt(drm_enc); DPU_DEBUG_ENC(dpu_enc, "\n"); + + mutex_lock(&dpu_enc->enc_lock); + dpu_enc->enabled = false; priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); @@ -1242,17 +1232,23 @@ /* wait for idle */ dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) { + if (msm_dp_display_pre_disable(priv->dp, drm_enc)) + DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n"); + } + dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.disable) + if (phys->ops.disable) phys->ops.disable(phys); } + /* after phys waits for frame-done, should be no more frames pending */ - if (atomic_xchg(&dpu_enc->frame_done_timeout, 0)) { + if (atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) { DPU_ERROR("enc%d timeout pending\n", drm_enc->base.id); del_timer_sync(&dpu_enc->frame_done_timer); } @@ -1260,15 +1256,17 @@ dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_STOP); for (i = 0; i < dpu_enc->num_phys_encs; i++) { - if (dpu_enc->phys_encs[i]) - dpu_enc->phys_encs[i]->connector = NULL; + dpu_enc->phys_encs[i]->connector = NULL; } - - dpu_enc->cur_master = NULL; DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); - dpu_rm_release(&dpu_kms->rm, drm_enc); + if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) { + if (msm_dp_display_disable(priv->dp, drm_enc)) + DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n"); + } + + mutex_unlock(&dpu_enc->enc_lock); } static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog, @@ -1299,8 +1297,8 @@ dpu_enc = to_dpu_encoder_virt(drm_enc); spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); - if (dpu_enc->crtc_vblank_cb) - dpu_enc->crtc_vblank_cb(dpu_enc->crtc_vblank_cb_data); + if (dpu_enc->crtc) + dpu_crtc_vblank_callback(dpu_enc->crtc); spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); atomic_inc(&phy_enc->vsync_cnt); @@ -1320,31 +1318,38 @@ DPU_ATRACE_END("encoder_underrun_callback"); } -void dpu_encoder_register_vblank_callback(struct drm_encoder *drm_enc, - void (*vbl_cb)(void *), void *vbl_data) +void dpu_encoder_assign_crtc(struct drm_encoder *drm_enc, struct drm_crtc *crtc) { struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); unsigned long lock_flags; - bool enable; + + spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); + /* crtc should always be cleared before re-assigning */ + WARN_ON(crtc && dpu_enc->crtc); + dpu_enc->crtc = crtc; + spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); +} + +void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *drm_enc, + struct drm_crtc *crtc, bool enable) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + unsigned long lock_flags; int i; - enable = vbl_cb ? true : false; - - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } trace_dpu_enc_vblank_cb(DRMID(drm_enc), enable); spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); - dpu_enc->crtc_vblank_cb = vbl_cb; - dpu_enc->crtc_vblank_cb_data = vbl_data; + if (dpu_enc->crtc != crtc) { + spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); + return; + } spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.control_vblank_irq) + if (phys->ops.control_vblank_irq) phys->ops.control_vblank_irq(phys, enable); } } @@ -1395,14 +1400,14 @@ /* One of the physical encoders has become idle */ for (i = 0; i < dpu_enc->num_phys_encs; i++) { if (dpu_enc->phys_encs[i] == ready_phys) { - clear_bit(i, dpu_enc->frame_busy_mask); trace_dpu_enc_frame_done_cb(DRMID(drm_enc), i, dpu_enc->frame_busy_mask[0]); + clear_bit(i, dpu_enc->frame_busy_mask); } } if (!dpu_enc->frame_busy_mask[0]) { - atomic_set(&dpu_enc->frame_done_timeout, 0); + atomic_set(&dpu_enc->frame_done_timeout_ms, 0); del_timer(&dpu_enc->frame_done_timer); dpu_encoder_resource_control(drm_enc, @@ -1420,7 +1425,7 @@ } } -static void dpu_encoder_off_work(struct kthread_work *work) +static void dpu_encoder_off_work(struct work_struct *work) { struct dpu_encoder_virt *dpu_enc = container_of(work, struct dpu_encoder_virt, delayed_off_work.work); @@ -1443,18 +1448,12 @@ * phys: Pointer to physical encoder structure * extra_flush_bits: Additional bit mask to include in flush trigger */ -static inline void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, +static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phys, uint32_t extra_flush_bits) { struct dpu_hw_ctl *ctl; int pending_kickoff_cnt; u32 ret = UINT_MAX; - - if (!drm_enc || !phys) { - DPU_ERROR("invalid argument(s), drm_enc %d, phys_enc %d\n", - drm_enc != 0, phys != 0); - return; - } if (!phys->hw_pp) { DPU_ERROR("invalid pingpong hw\n"); @@ -1462,7 +1461,7 @@ } ctl = phys->hw_ctl; - if (!ctl || !ctl->ops.trigger_flush) { + if (!ctl->ops.trigger_flush) { DPU_ERROR("missing trigger cb\n"); return; } @@ -1478,14 +1477,15 @@ ret = ctl->ops.get_pending_flush(ctl); trace_dpu_enc_trigger_flush(DRMID(drm_enc), phys->intf_idx, - pending_kickoff_cnt, ctl->idx, ret); + pending_kickoff_cnt, ctl->idx, + extra_flush_bits, ret); } /** * _dpu_encoder_trigger_start - trigger start for a physical encoder * phys: Pointer to physical encoder structure */ -static inline void _dpu_encoder_trigger_start(struct dpu_encoder_phys *phys) +static void _dpu_encoder_trigger_start(struct dpu_encoder_phys *phys) { if (!phys) { DPU_ERROR("invalid argument(s)\n"); @@ -1505,13 +1505,8 @@ { struct dpu_hw_ctl *ctl; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - ctl = phys_enc->hw_ctl; - if (ctl && ctl->ops.trigger_start) { + if (ctl->ops.trigger_start) { ctl->ops.trigger_start(ctl); trace_dpu_enc_trigger_start(DRMID(phys_enc->parent), ctl->idx); } @@ -1542,30 +1537,24 @@ return rc; } -void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) +static void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) { struct dpu_encoder_virt *dpu_enc; struct dpu_hw_ctl *ctl; int rc; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } dpu_enc = to_dpu_encoder_virt(phys_enc->parent); ctl = phys_enc->hw_ctl; - if (!ctl || !ctl->ops.reset) + if (!ctl->ops.reset) return; DRM_DEBUG_KMS("id:%u ctl %d reset\n", DRMID(phys_enc->parent), ctl->idx); rc = ctl->ops.reset(ctl); - if (rc) { + if (rc) DPU_ERROR_ENC(dpu_enc, "ctl %d reset failure\n", ctl->idx); - dpu_dbg_dump(false, __func__, true, true); - } phys_enc->enable_state = DPU_ENC_ENABLED; } @@ -1585,11 +1574,6 @@ uint32_t i, pending_flush; unsigned long lock_flags; - if (!dpu_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - pending_flush = 0x0; /* update pending counts and trigger kickoff ctl flush atomically */ @@ -1599,15 +1583,19 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (!phys || phys->enable_state == DPU_ENC_DISABLED) + if (phys->enable_state == DPU_ENC_DISABLED) continue; ctl = phys->hw_ctl; - if (!ctl) - continue; + /* + * This is cleared in frame_done worker, which isn't invoked + * for async commits. So don't set this for async, since it'll + * roll over to the next commit. + */ if (phys->split_role != ENC_ROLE_SLAVE) set_bit(i, dpu_enc->frame_busy_mask); + if (!phys->ops.needs_single_flush || !phys->ops.needs_single_flush(phys)) _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0); @@ -1646,17 +1634,15 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys && phys->hw_ctl) { - ctl = phys->hw_ctl; - if (ctl->ops.clear_pending_flush) - ctl->ops.clear_pending_flush(ctl); + ctl = phys->hw_ctl; + if (ctl->ops.clear_pending_flush) + ctl->ops.clear_pending_flush(ctl); - /* update only for command mode primary ctl */ - if ((phys == dpu_enc->cur_master) && - (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) - && ctl->ops.trigger_pending) - ctl->ops.trigger_pending(ctl); - } + /* update only for command mode primary ctl */ + if ((phys == dpu_enc->cur_master) && + (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + && ctl->ops.trigger_pending) + ctl->ops.trigger_pending(ctl); } } @@ -1707,8 +1693,7 @@ return line_time; } -static int _dpu_encoder_wakeup_time(struct drm_encoder *drm_enc, - ktime_t *wakeup_time) +int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time) { struct drm_display_mode *mode; struct dpu_encoder_virt *dpu_enc; @@ -1762,8 +1747,7 @@ struct msm_drm_private *priv; struct msm_drm_thread *event_thread; - if (!drm_enc->dev || !drm_enc->dev->dev_private || - !drm_enc->crtc) { + if (!drm_enc->dev || !drm_enc->crtc) { DPU_ERROR("invalid parameters\n"); return; } @@ -1795,7 +1779,7 @@ return; } - if (_dpu_encoder_wakeup_time(&dpu_enc->base, &wakeup_time)) + if (dpu_encoder_vsync_time(&dpu_enc->base, &wakeup_time)) return; trace_dpu_enc_vsync_event_work(DRMID(&dpu_enc->base), wakeup_time); @@ -1803,18 +1787,13 @@ nsecs_to_jiffies(ktime_to_ns(wakeup_time))); } -void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, - struct dpu_encoder_kickoff_params *params) +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; bool needs_hw_reset = false; unsigned int i; - if (!drm_enc || !params) { - DPU_ERROR("invalid args\n"); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); trace_dpu_enc_prepare_kickoff(DRMID(drm_enc)); @@ -1823,12 +1802,10 @@ DPU_ATRACE_BEGIN("enc_prepare_for_kickoff"); for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys) { - if (phys->ops.prepare_for_kickoff) - phys->ops.prepare_for_kickoff(phys, params); - if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) - needs_hw_reset = true; - } + if (phys->ops.prepare_for_kickoff) + phys->ops.prepare_for_kickoff(phys); + if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) + needs_hw_reset = true; } DPU_ATRACE_END("enc_prepare_for_kickoff"); @@ -1838,9 +1815,7 @@ if (needs_hw_reset) { trace_dpu_enc_prepare_kickoff_reset(DRMID(drm_enc)); for (i = 0; i < dpu_enc->num_phys_encs; i++) { - phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.hw_reset) - phys->ops.hw_reset(phys); + dpu_encoder_helper_hw_reset(dpu_enc->phys_encs[i]); } } } @@ -1850,22 +1825,20 @@ struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; ktime_t wakeup_time; + unsigned long timeout_ms; unsigned int i; - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } DPU_ATRACE_BEGIN("encoder_kickoff"); dpu_enc = to_dpu_encoder_virt(drm_enc); trace_dpu_enc_kickoff(DRMID(drm_enc)); - atomic_set(&dpu_enc->frame_done_timeout, - DPU_FRAME_DONE_TIMEOUT * 1000 / - drm_enc->crtc->state->adjusted_mode.vrefresh); - mod_timer(&dpu_enc->frame_done_timer, jiffies + - ((atomic_read(&dpu_enc->frame_done_timeout) * HZ) / 1000)); + timeout_ms = DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES * 1000 / + drm_mode_vrefresh(&drm_enc->crtc->state->adjusted_mode); + + atomic_set(&dpu_enc->frame_done_timeout_ms, timeout_ms); + mod_timer(&dpu_enc->frame_done_timer, + jiffies + msecs_to_jiffies(timeout_ms)); /* All phys encs are ready to go, trigger the kickoff */ _dpu_encoder_kickoff_phys(dpu_enc); @@ -1873,12 +1846,12 @@ /* allow phys encs to handle any post-kickoff business */ for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.handle_post_kickoff) + if (phys->ops.handle_post_kickoff) phys->ops.handle_post_kickoff(phys); } - if (dpu_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI && - !_dpu_encoder_wakeup_time(drm_enc, &wakeup_time)) { + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI && + !dpu_encoder_vsync_time(drm_enc, &wakeup_time)) { trace_dpu_enc_early_kickoff(DRMID(drm_enc), ktime_to_ms(wakeup_time)); mod_timer(&dpu_enc->vsync_event_timer, @@ -1902,7 +1875,7 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.prepare_commit) + if (phys->ops.prepare_commit) phys->ops.prepare_commit(phys); } } @@ -1910,20 +1883,12 @@ #ifdef CONFIG_DEBUG_FS static int _dpu_encoder_status_show(struct seq_file *s, void *data) { - struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_virt *dpu_enc = s->private; int i; - - if (!s || !s->private) - return -EINVAL; - - dpu_enc = s->private; mutex_lock(&dpu_enc->enc_lock); for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (!phys) - continue; seq_printf(s, "intf:%d vsync:%8d underrun:%8d ", phys->intf_idx - INTF_0, @@ -1947,193 +1912,42 @@ return 0; } -static int _dpu_encoder_debugfs_status_open(struct inode *inode, - struct file *file) -{ - return single_open(file, _dpu_encoder_status_show, inode->i_private); -} - -static ssize_t _dpu_encoder_misr_setup(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct dpu_encoder_virt *dpu_enc; - int i = 0, rc; - char buf[MISR_BUFF_SIZE + 1]; - size_t buff_copy; - u32 frame_count, enable; - - if (!file || !file->private_data) - return -EINVAL; - - dpu_enc = file->private_data; - - buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); - if (copy_from_user(buf, user_buf, buff_copy)) - return -EINVAL; - - buf[buff_copy] = 0; /* end of string */ - - if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) - return -EINVAL; - - rc = _dpu_encoder_power_enable(dpu_enc, true); - if (rc) - return rc; - - mutex_lock(&dpu_enc->enc_lock); - dpu_enc->misr_enable = enable; - dpu_enc->misr_frame_count = frame_count; - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (!phys || !phys->ops.setup_misr) - continue; - - phys->ops.setup_misr(phys, enable, frame_count); - } - mutex_unlock(&dpu_enc->enc_lock); - _dpu_encoder_power_enable(dpu_enc, false); - - return count; -} - -static ssize_t _dpu_encoder_misr_read(struct file *file, - char __user *user_buff, size_t count, loff_t *ppos) -{ - struct dpu_encoder_virt *dpu_enc; - int i = 0, len = 0; - char buf[MISR_BUFF_SIZE + 1] = {'\0'}; - int rc; - - if (*ppos) - return 0; - - if (!file || !file->private_data) - return -EINVAL; - - dpu_enc = file->private_data; - - rc = _dpu_encoder_power_enable(dpu_enc, true); - if (rc) - return rc; - - mutex_lock(&dpu_enc->enc_lock); - if (!dpu_enc->misr_enable) { - len += snprintf(buf + len, MISR_BUFF_SIZE - len, - "disabled\n"); - goto buff_check; - } else if (dpu_enc->disp_info.capabilities & - ~MSM_DISPLAY_CAP_VID_MODE) { - len += snprintf(buf + len, MISR_BUFF_SIZE - len, - "unsupported\n"); - goto buff_check; - } - - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (!phys || !phys->ops.collect_misr) - continue; - - len += snprintf(buf + len, MISR_BUFF_SIZE - len, - "Intf idx:%d\n", phys->intf_idx - INTF_0); - len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n", - phys->ops.collect_misr(phys)); - } - -buff_check: - if (count <= len) { - len = 0; - goto end; - } - - if (copy_to_user(user_buff, buf, len)) { - len = -EFAULT; - goto end; - } - - *ppos += len; /* increase offset */ - -end: - mutex_unlock(&dpu_enc->enc_lock); - _dpu_encoder_power_enable(dpu_enc, false); - return len; -} +DEFINE_SHOW_ATTRIBUTE(_dpu_encoder_status); static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) { - struct dpu_encoder_virt *dpu_enc; - struct msm_drm_private *priv; - struct dpu_kms *dpu_kms; + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); int i; - - static const struct file_operations debugfs_status_fops = { - .open = _dpu_encoder_debugfs_status_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - }; - - static const struct file_operations debugfs_misr_fops = { - .open = simple_open, - .read = _dpu_encoder_misr_read, - .write = _dpu_encoder_misr_setup, - }; char name[DPU_NAME_SIZE]; - if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + if (!drm_enc->dev) { DPU_ERROR("invalid encoder or kms\n"); return -EINVAL; } - - dpu_enc = to_dpu_encoder_virt(drm_enc); - priv = drm_enc->dev->dev_private; - dpu_kms = to_dpu_kms(priv->kms); snprintf(name, DPU_NAME_SIZE, "encoder%u", drm_enc->base.id); /* create overall sub-directory for the encoder */ dpu_enc->debugfs_root = debugfs_create_dir(name, drm_enc->dev->primary->debugfs_root); - if (!dpu_enc->debugfs_root) - return -ENOMEM; /* don't error check these */ debugfs_create_file("status", 0600, - dpu_enc->debugfs_root, dpu_enc, &debugfs_status_fops); - - debugfs_create_file("misr_data", 0600, - dpu_enc->debugfs_root, dpu_enc, &debugfs_misr_fops); + dpu_enc->debugfs_root, dpu_enc, &_dpu_encoder_status_fops); for (i = 0; i < dpu_enc->num_phys_encs; i++) - if (dpu_enc->phys_encs[i] && - dpu_enc->phys_encs[i]->ops.late_register) + if (dpu_enc->phys_encs[i]->ops.late_register) dpu_enc->phys_encs[i]->ops.late_register( dpu_enc->phys_encs[i], dpu_enc->debugfs_root); return 0; } - -static void _dpu_encoder_destroy_debugfs(struct drm_encoder *drm_enc) -{ - struct dpu_encoder_virt *dpu_enc; - - if (!drm_enc) - return; - - dpu_enc = to_dpu_encoder_virt(drm_enc); - debugfs_remove_recursive(dpu_enc->debugfs_root); -} #else static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) { return 0; -} - -static void _dpu_encoder_destroy_debugfs(struct drm_encoder *drm_enc) -{ } #endif @@ -2144,7 +1958,9 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder) { - _dpu_encoder_destroy_debugfs(encoder); + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(encoder); + + debugfs_remove_recursive(dpu_enc->debugfs_root); } static int dpu_encoder_virt_add_phys_encs( @@ -2173,7 +1989,7 @@ if (IS_ERR_OR_NULL(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n", PTR_ERR(enc)); - return enc == 0 ? -EINVAL : PTR_ERR(enc); + return enc == NULL ? -EINVAL : PTR_ERR(enc); } dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; @@ -2186,12 +2002,17 @@ if (IS_ERR_OR_NULL(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n", PTR_ERR(enc)); - return enc == 0 ? -EINVAL : PTR_ERR(enc); + return enc == NULL ? -EINVAL : PTR_ERR(enc); } dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; ++dpu_enc->num_phys_encs; } + + if (params->split_role == ENC_ROLE_SLAVE) + dpu_enc->cur_slave = enc; + else + dpu_enc->cur_master = enc; return 0; } @@ -2204,19 +2025,19 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, struct dpu_kms *dpu_kms, - struct msm_display_info *disp_info, - int *drm_enc_mode) + struct msm_display_info *disp_info) { int ret = 0; int i = 0; - enum dpu_intf_type intf_type; + enum dpu_intf_type intf_type = INTF_NONE; struct dpu_enc_phys_init_params phys_params; - if (!dpu_enc || !dpu_kms) { - DPU_ERROR("invalid arg(s), enc %d kms %d\n", - dpu_enc != 0, dpu_kms != 0); + if (!dpu_enc) { + DPU_ERROR("invalid arg(s), enc %d\n", dpu_enc != NULL); return -EINVAL; } + + dpu_enc->cur_master = NULL; memset(&phys_params, 0, sizeof(phys_params)); phys_params.dpu_kms = dpu_kms; @@ -2226,23 +2047,16 @@ DPU_DEBUG("\n"); - if (disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) { - *drm_enc_mode = DRM_MODE_ENCODER_DSI; + switch (disp_info->intf_type) { + case DRM_MODE_ENCODER_DSI: intf_type = INTF_DSI; - } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_HDMIA) { - *drm_enc_mode = DRM_MODE_ENCODER_TMDS; - intf_type = INTF_HDMI; - } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_DisplayPort) { - *drm_enc_mode = DRM_MODE_ENCODER_TMDS; + break; + case DRM_MODE_ENCODER_TMDS: intf_type = INTF_DP; - } else { - DPU_ERROR_ENC(dpu_enc, "unsupported display interface type\n"); - return -EINVAL; + break; } WARN_ON(disp_info->num_of_h_tiles < 1); - - dpu_enc->display_num_of_h_tiles = disp_info->num_of_h_tiles; DPU_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles); @@ -2292,11 +2106,8 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (phys) { - atomic_set(&phys->vsync_cnt, 0); - atomic_set(&phys->underrun_cnt, 0); - } + atomic_set(&phys->vsync_cnt, 0); + atomic_set(&phys->underrun_cnt, 0); } mutex_unlock(&dpu_enc->enc_lock); @@ -2308,20 +2119,18 @@ struct dpu_encoder_virt *dpu_enc = from_timer(dpu_enc, t, frame_done_timer); struct drm_encoder *drm_enc = &dpu_enc->base; - struct msm_drm_private *priv; u32 event; - if (!drm_enc->dev || !drm_enc->dev->dev_private) { + if (!drm_enc->dev) { DPU_ERROR("invalid parameters\n"); return; } - priv = drm_enc->dev->dev_private; if (!dpu_enc->frame_busy_mask[0] || !dpu_enc->crtc_frame_event_cb) { DRM_DEBUG_KMS("id:%u invalid timeout frame_busy_mask=%lu\n", DRMID(drm_enc), dpu_enc->frame_busy_mask[0]); return; - } else if (!atomic_xchg(&dpu_enc->frame_done_timeout, 0)) { + } else if (!atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) { DRM_DEBUG_KMS("id:%u invalid timeout\n", DRMID(drm_enc)); return; } @@ -2356,32 +2165,25 @@ struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct drm_encoder *drm_enc = NULL; struct dpu_encoder_virt *dpu_enc = NULL; - int drm_enc_mode = DRM_MODE_ENCODER_NONE; int ret = 0; dpu_enc = to_dpu_encoder_virt(enc); - mutex_init(&dpu_enc->enc_lock); - ret = dpu_encoder_setup_display(dpu_enc, dpu_kms, disp_info, - &drm_enc_mode); + ret = dpu_encoder_setup_display(dpu_enc, dpu_kms, disp_info); if (ret) goto fail; - dpu_enc->cur_master = NULL; - spin_lock_init(&dpu_enc->enc_spinlock); - - atomic_set(&dpu_enc->frame_done_timeout, 0); + atomic_set(&dpu_enc->frame_done_timeout_ms, 0); timer_setup(&dpu_enc->frame_done_timer, dpu_encoder_frame_done_timeout, 0); - if (disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) + if (disp_info->intf_type == DRM_MODE_ENCODER_DSI) timer_setup(&dpu_enc->vsync_event_timer, dpu_encoder_vsync_event_handler, 0); - mutex_init(&dpu_enc->rc_lock); - kthread_init_delayed_work(&dpu_enc->delayed_off_work, + INIT_DELAYED_WORK(&dpu_enc->delayed_off_work, dpu_encoder_off_work); dpu_enc->idle_timeout = IDLE_TIMEOUT; @@ -2423,6 +2225,11 @@ drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs); + spin_lock_init(&dpu_enc->enc_spinlock); + dpu_enc->enabled = false; + mutex_init(&dpu_enc->enc_lock); + mutex_init(&dpu_enc->rc_lock); + return &dpu_enc->base; } @@ -2442,8 +2249,6 @@ for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (!phys) - continue; switch (event) { case MSM_ENC_COMMIT_DONE: @@ -2459,7 +2264,7 @@ DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n", event); return -EINVAL; - }; + } if (fn_wait) { DPU_ATRACE_BEGIN("wait_for_completion_event"); @@ -2476,7 +2281,6 @@ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder) { struct dpu_encoder_virt *dpu_enc = NULL; - int i; if (!encoder) { DPU_ERROR("invalid encoder\n"); @@ -2487,12 +2291,8 @@ if (dpu_enc->cur_master) return dpu_enc->cur_master->intf_mode; - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (phys) - return phys->intf_mode; - } + if (dpu_enc->num_phys_encs) + return dpu_enc->phys_encs[0]->intf_mode; return INTF_MODE_NONE; } -- Gitblit v1.6.2