1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 225fdd593SJeykumar Sankaran /* 358fc5d18SJessica Zhang * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 478d9b458SJessica Zhang * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 525fdd593SJeykumar Sankaran * Copyright (C) 2013 Red Hat 625fdd593SJeykumar Sankaran * Author: Rob Clark <robdclark@gmail.com> 725fdd593SJeykumar Sankaran */ 825fdd593SJeykumar Sankaran 925fdd593SJeykumar Sankaran #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 1025fdd593SJeykumar Sankaran #include <linux/sort.h> 1125fdd593SJeykumar Sankaran #include <linux/debugfs.h> 1225fdd593SJeykumar Sankaran #include <linux/ktime.h> 134259ff7aSKalyan Thota #include <linux/bits.h> 14feea39a8SSam Ravnborg 15351f950dSMaxime Ripard #include <drm/drm_atomic.h> 1625fdd593SJeykumar Sankaran #include <drm/drm_crtc.h> 1725fdd593SJeykumar Sankaran #include <drm/drm_flip_work.h> 18fcd70cd3SDaniel Vetter #include <drm/drm_mode.h> 19fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 2025fdd593SJeykumar Sankaran #include <drm/drm_rect.h> 21feea39a8SSam Ravnborg #include <drm/drm_vblank.h> 2225fdd593SJeykumar Sankaran 2325fdd593SJeykumar Sankaran #include "dpu_kms.h" 2425fdd593SJeykumar Sankaran #include "dpu_hw_lm.h" 2525fdd593SJeykumar Sankaran #include "dpu_hw_ctl.h" 264259ff7aSKalyan Thota #include "dpu_hw_dspp.h" 2725fdd593SJeykumar Sankaran #include "dpu_crtc.h" 2825fdd593SJeykumar Sankaran #include "dpu_plane.h" 2925fdd593SJeykumar Sankaran #include "dpu_encoder.h" 3025fdd593SJeykumar Sankaran #include "dpu_vbif.h" 3125fdd593SJeykumar Sankaran #include "dpu_core_perf.h" 3225fdd593SJeykumar Sankaran #include "dpu_trace.h" 3325fdd593SJeykumar Sankaran 3425fdd593SJeykumar Sankaran /* layer mixer index on dpu_crtc */ 3525fdd593SJeykumar Sankaran #define LEFT_MIXER 0 3625fdd593SJeykumar Sankaran #define RIGHT_MIXER 1 3725fdd593SJeykumar Sankaran 3870df9610SSean Paul /* timeout in ms waiting for frame done */ 3970df9610SSean Paul #define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 4070df9610SSean Paul 414259ff7aSKalyan Thota #define CONVERT_S3_15(val) \ 424259ff7aSKalyan Thota (((((u64)val) & ~BIT_ULL(63)) >> 17) & GENMASK_ULL(17, 0)) 434259ff7aSKalyan Thota 4458fba464SSean Paul static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) 4525fdd593SJeykumar Sankaran { 4604b96b63SBruce Wang struct msm_drm_private *priv = crtc->dev->dev_private; 4725fdd593SJeykumar Sankaran 4825fdd593SJeykumar Sankaran return to_dpu_kms(priv->kms); 4925fdd593SJeykumar Sankaran } 5025fdd593SJeykumar Sankaran 5125fdd593SJeykumar Sankaran static void dpu_crtc_destroy(struct drm_crtc *crtc) 5225fdd593SJeykumar Sankaran { 5325fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 5425fdd593SJeykumar Sankaran 5525fdd593SJeykumar Sankaran if (!crtc) 5625fdd593SJeykumar Sankaran return; 5725fdd593SJeykumar Sankaran 5825fdd593SJeykumar Sankaran drm_crtc_cleanup(crtc); 5925fdd593SJeykumar Sankaran kfree(dpu_crtc); 6025fdd593SJeykumar Sankaran } 6125fdd593SJeykumar Sankaran 6273743e72SKalyan Thota static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) 6373743e72SKalyan Thota { 6473743e72SKalyan Thota struct drm_device *dev = crtc->dev; 6573743e72SKalyan Thota struct drm_encoder *encoder; 6673743e72SKalyan Thota 6773743e72SKalyan Thota drm_for_each_encoder(encoder, dev) 6873743e72SKalyan Thota if (encoder->crtc == crtc) 6973743e72SKalyan Thota return encoder; 7073743e72SKalyan Thota 7173743e72SKalyan Thota return NULL; 7273743e72SKalyan Thota } 7373743e72SKalyan Thota 7478d9b458SJessica Zhang static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name) 7578d9b458SJessica Zhang { 7678d9b458SJessica Zhang if (!src_name || 7778d9b458SJessica Zhang !strcmp(src_name, "none")) 7878d9b458SJessica Zhang return DPU_CRTC_CRC_SOURCE_NONE; 7978d9b458SJessica Zhang if (!strcmp(src_name, "auto") || 8078d9b458SJessica Zhang !strcmp(src_name, "lm")) 8178d9b458SJessica Zhang return DPU_CRTC_CRC_SOURCE_LAYER_MIXER; 82*b1665047SJessica Zhang if (!strcmp(src_name, "encoder")) 83*b1665047SJessica Zhang return DPU_CRTC_CRC_SOURCE_ENCODER; 8478d9b458SJessica Zhang 8578d9b458SJessica Zhang return DPU_CRTC_CRC_SOURCE_INVALID; 8678d9b458SJessica Zhang } 8778d9b458SJessica Zhang 8878d9b458SJessica Zhang static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, 8978d9b458SJessica Zhang const char *src_name, size_t *values_cnt) 9078d9b458SJessica Zhang { 9178d9b458SJessica Zhang enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); 9278d9b458SJessica Zhang struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); 9378d9b458SJessica Zhang 9478d9b458SJessica Zhang if (source < 0) { 9578d9b458SJessica Zhang DRM_DEBUG_DRIVER("Invalid source %s for CRTC%d\n", src_name, crtc->index); 9678d9b458SJessica Zhang return -EINVAL; 9778d9b458SJessica Zhang } 9878d9b458SJessica Zhang 99*b1665047SJessica Zhang if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { 10078d9b458SJessica Zhang *values_cnt = crtc_state->num_mixers; 101*b1665047SJessica Zhang } else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) { 102*b1665047SJessica Zhang struct drm_encoder *drm_enc; 103*b1665047SJessica Zhang 104*b1665047SJessica Zhang *values_cnt = 0; 105*b1665047SJessica Zhang 106*b1665047SJessica Zhang drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) 107*b1665047SJessica Zhang *values_cnt += dpu_encoder_get_crc_values_cnt(drm_enc); 108*b1665047SJessica Zhang } 10978d9b458SJessica Zhang 11078d9b458SJessica Zhang return 0; 11178d9b458SJessica Zhang } 11278d9b458SJessica Zhang 11358fc5d18SJessica Zhang static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) 11458fc5d18SJessica Zhang { 11558fc5d18SJessica Zhang struct dpu_crtc_mixer *m; 11658fc5d18SJessica Zhang int i; 11758fc5d18SJessica Zhang 11858fc5d18SJessica Zhang for (i = 0; i < crtc_state->num_mixers; ++i) { 11958fc5d18SJessica Zhang m = &crtc_state->mixers[i]; 12058fc5d18SJessica Zhang 12158fc5d18SJessica Zhang if (!m->hw_lm || !m->hw_lm->ops.setup_misr) 12258fc5d18SJessica Zhang continue; 12358fc5d18SJessica Zhang 12458fc5d18SJessica Zhang /* Calculate MISR over 1 frame */ 12558fc5d18SJessica Zhang m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); 12658fc5d18SJessica Zhang } 12758fc5d18SJessica Zhang } 12858fc5d18SJessica Zhang 129*b1665047SJessica Zhang static void dpu_crtc_setup_encoder_misr(struct drm_crtc *crtc) 130*b1665047SJessica Zhang { 131*b1665047SJessica Zhang struct drm_encoder *drm_enc; 132*b1665047SJessica Zhang 133*b1665047SJessica Zhang drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) 134*b1665047SJessica Zhang dpu_encoder_setup_misr(drm_enc); 135*b1665047SJessica Zhang } 136*b1665047SJessica Zhang 13778d9b458SJessica Zhang static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) 13878d9b458SJessica Zhang { 13978d9b458SJessica Zhang enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); 14078d9b458SJessica Zhang enum dpu_crtc_crc_source current_source; 14178d9b458SJessica Zhang struct dpu_crtc_state *crtc_state; 14278d9b458SJessica Zhang struct drm_device *drm_dev = crtc->dev; 14378d9b458SJessica Zhang 14478d9b458SJessica Zhang bool was_enabled; 14578d9b458SJessica Zhang bool enable = false; 14658fc5d18SJessica Zhang int ret = 0; 14778d9b458SJessica Zhang 14878d9b458SJessica Zhang if (source < 0) { 14978d9b458SJessica Zhang DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index); 15078d9b458SJessica Zhang return -EINVAL; 15178d9b458SJessica Zhang } 15278d9b458SJessica Zhang 15378d9b458SJessica Zhang ret = drm_modeset_lock(&crtc->mutex, NULL); 15478d9b458SJessica Zhang 15578d9b458SJessica Zhang if (ret) 15678d9b458SJessica Zhang return ret; 15778d9b458SJessica Zhang 15878d9b458SJessica Zhang enable = (source != DPU_CRTC_CRC_SOURCE_NONE); 15978d9b458SJessica Zhang crtc_state = to_dpu_crtc_state(crtc->state); 16078d9b458SJessica Zhang 16178d9b458SJessica Zhang spin_lock_irq(&drm_dev->event_lock); 16278d9b458SJessica Zhang current_source = crtc_state->crc_source; 16378d9b458SJessica Zhang spin_unlock_irq(&drm_dev->event_lock); 16478d9b458SJessica Zhang 16578d9b458SJessica Zhang was_enabled = (current_source != DPU_CRTC_CRC_SOURCE_NONE); 16678d9b458SJessica Zhang 16778d9b458SJessica Zhang if (!was_enabled && enable) { 16878d9b458SJessica Zhang ret = drm_crtc_vblank_get(crtc); 16978d9b458SJessica Zhang 17078d9b458SJessica Zhang if (ret) 17178d9b458SJessica Zhang goto cleanup; 17278d9b458SJessica Zhang 17378d9b458SJessica Zhang } else if (was_enabled && !enable) { 17478d9b458SJessica Zhang drm_crtc_vblank_put(crtc); 17578d9b458SJessica Zhang } 17678d9b458SJessica Zhang 17778d9b458SJessica Zhang spin_lock_irq(&drm_dev->event_lock); 17878d9b458SJessica Zhang crtc_state->crc_source = source; 17978d9b458SJessica Zhang spin_unlock_irq(&drm_dev->event_lock); 18078d9b458SJessica Zhang 18178d9b458SJessica Zhang crtc_state->crc_frame_skip_count = 0; 18278d9b458SJessica Zhang 18358fc5d18SJessica Zhang if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) 18458fc5d18SJessica Zhang dpu_crtc_setup_lm_misr(crtc_state); 185*b1665047SJessica Zhang else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) 186*b1665047SJessica Zhang dpu_crtc_setup_encoder_misr(crtc); 18758fc5d18SJessica Zhang else 18858fc5d18SJessica Zhang ret = -EINVAL; 18978d9b458SJessica Zhang 19078d9b458SJessica Zhang cleanup: 19178d9b458SJessica Zhang drm_modeset_unlock(&crtc->mutex); 19278d9b458SJessica Zhang 19378d9b458SJessica Zhang return ret; 19478d9b458SJessica Zhang } 19578d9b458SJessica Zhang 19673743e72SKalyan Thota static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) 19773743e72SKalyan Thota { 198885455d6SMark Yacoub struct drm_encoder *encoder = get_encoder_from_crtc(crtc); 19973743e72SKalyan Thota if (!encoder) { 20073743e72SKalyan Thota DRM_ERROR("no encoder found for crtc %d\n", crtc->index); 201885455d6SMark Yacoub return 0; 20273743e72SKalyan Thota } 20373743e72SKalyan Thota 204885455d6SMark Yacoub return dpu_encoder_get_vsync_count(encoder); 20573743e72SKalyan Thota } 20673743e72SKalyan Thota 20758fc5d18SJessica Zhang static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, 20858fc5d18SJessica Zhang struct dpu_crtc_state *crtc_state) 20978d9b458SJessica Zhang { 21078d9b458SJessica Zhang struct dpu_crtc_mixer *m; 21100326bfaSRob Clark u32 crcs[CRTC_DUAL_MIXERS]; 21278d9b458SJessica Zhang 21378d9b458SJessica Zhang int rc = 0; 21458fc5d18SJessica Zhang int i; 21578d9b458SJessica Zhang 21600326bfaSRob Clark BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers)); 21778d9b458SJessica Zhang 21878d9b458SJessica Zhang for (i = 0; i < crtc_state->num_mixers; ++i) { 21978d9b458SJessica Zhang 22078d9b458SJessica Zhang m = &crtc_state->mixers[i]; 22178d9b458SJessica Zhang 22278d9b458SJessica Zhang if (!m->hw_lm || !m->hw_lm->ops.collect_misr) 22378d9b458SJessica Zhang continue; 22478d9b458SJessica Zhang 22578d9b458SJessica Zhang rc = m->hw_lm->ops.collect_misr(m->hw_lm, &crcs[i]); 22678d9b458SJessica Zhang 22778d9b458SJessica Zhang if (rc) { 2283ce8bdcaSJessica Zhang if (rc != -ENODATA) 22978d9b458SJessica Zhang DRM_DEBUG_DRIVER("MISR read failed\n"); 23078d9b458SJessica Zhang return rc; 23178d9b458SJessica Zhang } 23200326bfaSRob Clark } 23300326bfaSRob Clark 23400326bfaSRob Clark return drm_crtc_add_crc_entry(crtc, true, 23500326bfaSRob Clark drm_crtc_accurate_vblank_count(crtc), crcs); 23600326bfaSRob Clark } 23778d9b458SJessica Zhang 238*b1665047SJessica Zhang static int dpu_crtc_get_encoder_crc(struct drm_crtc *crtc) 239*b1665047SJessica Zhang { 240*b1665047SJessica Zhang struct drm_encoder *drm_enc; 241*b1665047SJessica Zhang int rc, pos = 0; 242*b1665047SJessica Zhang u32 crcs[INTF_MAX]; 243*b1665047SJessica Zhang 244*b1665047SJessica Zhang drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) { 245*b1665047SJessica Zhang rc = dpu_encoder_get_crc(drm_enc, crcs, pos); 246*b1665047SJessica Zhang if (rc < 0) { 247*b1665047SJessica Zhang if (rc != -ENODATA) 248*b1665047SJessica Zhang DRM_DEBUG_DRIVER("MISR read failed\n"); 249*b1665047SJessica Zhang 250*b1665047SJessica Zhang return rc; 251*b1665047SJessica Zhang } 252*b1665047SJessica Zhang 253*b1665047SJessica Zhang pos += rc; 254*b1665047SJessica Zhang } 255*b1665047SJessica Zhang 256*b1665047SJessica Zhang return drm_crtc_add_crc_entry(crtc, true, 257*b1665047SJessica Zhang drm_crtc_accurate_vblank_count(crtc), crcs); 258*b1665047SJessica Zhang } 259*b1665047SJessica Zhang 26058fc5d18SJessica Zhang static int dpu_crtc_get_crc(struct drm_crtc *crtc) 26158fc5d18SJessica Zhang { 26258fc5d18SJessica Zhang struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); 26358fc5d18SJessica Zhang 26458fc5d18SJessica Zhang /* Skip first 2 frames in case of "uncooked" CRCs */ 26558fc5d18SJessica Zhang if (crtc_state->crc_frame_skip_count < 2) { 26658fc5d18SJessica Zhang crtc_state->crc_frame_skip_count++; 26758fc5d18SJessica Zhang return 0; 26858fc5d18SJessica Zhang } 26958fc5d18SJessica Zhang 27058fc5d18SJessica Zhang if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) 27158fc5d18SJessica Zhang return dpu_crtc_get_lm_crc(crtc, crtc_state); 272*b1665047SJessica Zhang else if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_ENCODER) 273*b1665047SJessica Zhang return dpu_crtc_get_encoder_crc(crtc); 27458fc5d18SJessica Zhang 27558fc5d18SJessica Zhang return -EINVAL; 27658fc5d18SJessica Zhang } 27758fc5d18SJessica Zhang 27873743e72SKalyan Thota static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, 27973743e72SKalyan Thota bool in_vblank_irq, 28073743e72SKalyan Thota int *vpos, int *hpos, 28173743e72SKalyan Thota ktime_t *stime, ktime_t *etime, 28273743e72SKalyan Thota const struct drm_display_mode *mode) 28373743e72SKalyan Thota { 28473743e72SKalyan Thota unsigned int pipe = crtc->index; 28573743e72SKalyan Thota struct drm_encoder *encoder; 28673743e72SKalyan Thota int line, vsw, vbp, vactive_start, vactive_end, vfp_end; 28773743e72SKalyan Thota 28873743e72SKalyan Thota encoder = get_encoder_from_crtc(crtc); 28973743e72SKalyan Thota if (!encoder) { 29073743e72SKalyan Thota DRM_ERROR("no encoder found for crtc %d\n", pipe); 29173743e72SKalyan Thota return false; 29273743e72SKalyan Thota } 29373743e72SKalyan Thota 29473743e72SKalyan Thota vsw = mode->crtc_vsync_end - mode->crtc_vsync_start; 29573743e72SKalyan Thota vbp = mode->crtc_vtotal - mode->crtc_vsync_end; 29673743e72SKalyan Thota 29773743e72SKalyan Thota /* 29873743e72SKalyan Thota * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at 29973743e72SKalyan Thota * the end of VFP. Translate the porch values relative to the line 30073743e72SKalyan Thota * counter positions. 30173743e72SKalyan Thota */ 30273743e72SKalyan Thota 30373743e72SKalyan Thota vactive_start = vsw + vbp + 1; 30473743e72SKalyan Thota vactive_end = vactive_start + mode->crtc_vdisplay; 30573743e72SKalyan Thota 30673743e72SKalyan Thota /* last scan line before VSYNC */ 30773743e72SKalyan Thota vfp_end = mode->crtc_vtotal; 30873743e72SKalyan Thota 30973743e72SKalyan Thota if (stime) 31073743e72SKalyan Thota *stime = ktime_get(); 31173743e72SKalyan Thota 31273743e72SKalyan Thota line = dpu_encoder_get_linecount(encoder); 31373743e72SKalyan Thota 31473743e72SKalyan Thota if (line < vactive_start) 31573743e72SKalyan Thota line -= vactive_start; 31673743e72SKalyan Thota else if (line > vactive_end) 31773743e72SKalyan Thota line = line - vfp_end - vactive_start; 31873743e72SKalyan Thota else 31973743e72SKalyan Thota line -= vactive_start; 32073743e72SKalyan Thota 32173743e72SKalyan Thota *vpos = line; 32273743e72SKalyan Thota *hpos = 0; 32373743e72SKalyan Thota 32473743e72SKalyan Thota if (etime) 32573743e72SKalyan Thota *etime = ktime_get(); 32673743e72SKalyan Thota 32773743e72SKalyan Thota return true; 32873743e72SKalyan Thota } 32973743e72SKalyan Thota 33025fdd593SJeykumar Sankaran static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, 33174593a28SSravanthi Kollukuduru struct dpu_plane_state *pstate, struct dpu_format *format) 33225fdd593SJeykumar Sankaran { 33325fdd593SJeykumar Sankaran struct dpu_hw_mixer *lm = mixer->hw_lm; 33474593a28SSravanthi Kollukuduru uint32_t blend_op; 335f964cfb7SDmitry Baryshkov uint32_t fg_alpha, bg_alpha; 336f964cfb7SDmitry Baryshkov 337f964cfb7SDmitry Baryshkov fg_alpha = pstate->base.alpha >> 8; 338f964cfb7SDmitry Baryshkov bg_alpha = 0xff - fg_alpha; 33925fdd593SJeykumar Sankaran 34025fdd593SJeykumar Sankaran /* default to opaque blending */ 341f964cfb7SDmitry Baryshkov if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE || 342f964cfb7SDmitry Baryshkov !format->alpha_enable) { 34374593a28SSravanthi Kollukuduru blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | 34474593a28SSravanthi Kollukuduru DPU_BLEND_BG_ALPHA_BG_CONST; 345f964cfb7SDmitry Baryshkov } else if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) { 346f964cfb7SDmitry Baryshkov blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | 347f964cfb7SDmitry Baryshkov DPU_BLEND_BG_ALPHA_FG_PIXEL; 348f964cfb7SDmitry Baryshkov if (fg_alpha != 0xff) { 349f964cfb7SDmitry Baryshkov bg_alpha = fg_alpha; 350f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_BG_MOD_ALPHA | 351f964cfb7SDmitry Baryshkov DPU_BLEND_BG_INV_MOD_ALPHA; 352f964cfb7SDmitry Baryshkov } else { 353f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_BG_INV_ALPHA; 354f964cfb7SDmitry Baryshkov } 355f964cfb7SDmitry Baryshkov } else { 35674593a28SSravanthi Kollukuduru /* coverage blending */ 35774593a28SSravanthi Kollukuduru blend_op = DPU_BLEND_FG_ALPHA_FG_PIXEL | 358f964cfb7SDmitry Baryshkov DPU_BLEND_BG_ALPHA_FG_PIXEL; 359f964cfb7SDmitry Baryshkov if (fg_alpha != 0xff) { 360f964cfb7SDmitry Baryshkov bg_alpha = fg_alpha; 361f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_FG_MOD_ALPHA | 362f964cfb7SDmitry Baryshkov DPU_BLEND_FG_INV_MOD_ALPHA | 363f964cfb7SDmitry Baryshkov DPU_BLEND_BG_MOD_ALPHA | 364f964cfb7SDmitry Baryshkov DPU_BLEND_BG_INV_MOD_ALPHA; 365f964cfb7SDmitry Baryshkov } else { 366f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_BG_INV_ALPHA; 367f964cfb7SDmitry Baryshkov } 36874593a28SSravanthi Kollukuduru } 36974593a28SSravanthi Kollukuduru 37074593a28SSravanthi Kollukuduru lm->ops.setup_blend_config(lm, pstate->stage, 371f964cfb7SDmitry Baryshkov fg_alpha, bg_alpha, blend_op); 37274593a28SSravanthi Kollukuduru 3735b702d78SStephen Boyd DRM_DEBUG_ATOMIC("format:%p4cc, alpha_en:%u blend_op:0x%x\n", 37492f1d09cSSakari Ailus &format->base.pixel_format, format->alpha_enable, blend_op); 37525fdd593SJeykumar Sankaran } 37625fdd593SJeykumar Sankaran 37725fdd593SJeykumar Sankaran static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) 37825fdd593SJeykumar Sankaran { 37925fdd593SJeykumar Sankaran struct dpu_crtc_state *crtc_state; 38025fdd593SJeykumar Sankaran int lm_idx, lm_horiz_position; 38125fdd593SJeykumar Sankaran 38225fdd593SJeykumar Sankaran crtc_state = to_dpu_crtc_state(crtc->state); 38325fdd593SJeykumar Sankaran 38425fdd593SJeykumar Sankaran lm_horiz_position = 0; 3859222cdd2SJeykumar Sankaran for (lm_idx = 0; lm_idx < crtc_state->num_mixers; lm_idx++) { 38625fdd593SJeykumar Sankaran const struct drm_rect *lm_roi = &crtc_state->lm_bounds[lm_idx]; 3879222cdd2SJeykumar Sankaran struct dpu_hw_mixer *hw_lm = crtc_state->mixers[lm_idx].hw_lm; 38825fdd593SJeykumar Sankaran struct dpu_hw_mixer_cfg cfg; 38925fdd593SJeykumar Sankaran 39025fdd593SJeykumar Sankaran if (!lm_roi || !drm_rect_visible(lm_roi)) 39125fdd593SJeykumar Sankaran continue; 39225fdd593SJeykumar Sankaran 39325fdd593SJeykumar Sankaran cfg.out_width = drm_rect_width(lm_roi); 39425fdd593SJeykumar Sankaran cfg.out_height = drm_rect_height(lm_roi); 39525fdd593SJeykumar Sankaran cfg.right_mixer = lm_horiz_position++; 39625fdd593SJeykumar Sankaran cfg.flags = 0; 39725fdd593SJeykumar Sankaran hw_lm->ops.setup_mixer_out(hw_lm, &cfg); 39825fdd593SJeykumar Sankaran } 39925fdd593SJeykumar Sankaran } 40025fdd593SJeykumar Sankaran 40125fdd593SJeykumar Sankaran static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, 40253c064a1SDmitry Baryshkov struct dpu_crtc *dpu_crtc, struct dpu_crtc_mixer *mixer, 40353c064a1SDmitry Baryshkov struct dpu_hw_stage_cfg *stage_cfg) 40425fdd593SJeykumar Sankaran { 40525fdd593SJeykumar Sankaran struct drm_plane *plane; 40625fdd593SJeykumar Sankaran struct drm_framebuffer *fb; 40725fdd593SJeykumar Sankaran struct drm_plane_state *state; 40804b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 40925fdd593SJeykumar Sankaran struct dpu_plane_state *pstate = NULL; 41025fdd593SJeykumar Sankaran struct dpu_format *format; 41104b96b63SBruce Wang struct dpu_hw_ctl *ctl = mixer->lm_ctl; 41225fdd593SJeykumar Sankaran 41325fdd593SJeykumar Sankaran u32 flush_mask; 41425fdd593SJeykumar Sankaran uint32_t stage_idx, lm_idx; 41525fdd593SJeykumar Sankaran int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 }; 41625fdd593SJeykumar Sankaran bool bg_alpha_enable = false; 417b3652e87SKrishna Manikandan DECLARE_BITMAP(fetch_active, SSPP_MAX); 41825fdd593SJeykumar Sankaran 419b3652e87SKrishna Manikandan memset(fetch_active, 0, sizeof(fetch_active)); 42025fdd593SJeykumar Sankaran drm_atomic_crtc_for_each_plane(plane, crtc) { 42125fdd593SJeykumar Sankaran state = plane->state; 42225fdd593SJeykumar Sankaran if (!state) 42325fdd593SJeykumar Sankaran continue; 42425fdd593SJeykumar Sankaran 42525fdd593SJeykumar Sankaran pstate = to_dpu_plane_state(state); 42625fdd593SJeykumar Sankaran fb = state->fb; 42725fdd593SJeykumar Sankaran 42825fdd593SJeykumar Sankaran dpu_plane_get_ctl_flush(plane, ctl, &flush_mask); 429b3652e87SKrishna Manikandan set_bit(dpu_plane_pipe(plane), fetch_active); 4305b702d78SStephen Boyd 4315b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc %d stage:%d - plane %d sspp %d fb %d\n", 43225fdd593SJeykumar Sankaran crtc->base.id, 43325fdd593SJeykumar Sankaran pstate->stage, 43425fdd593SJeykumar Sankaran plane->base.id, 43525fdd593SJeykumar Sankaran dpu_plane_pipe(plane) - SSPP_VIG0, 43625fdd593SJeykumar Sankaran state->fb ? state->fb->base.id : -1); 43725fdd593SJeykumar Sankaran 43825fdd593SJeykumar Sankaran format = to_dpu_format(msm_framebuffer_format(pstate->base.fb)); 43925fdd593SJeykumar Sankaran 44025fdd593SJeykumar Sankaran if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable) 44125fdd593SJeykumar Sankaran bg_alpha_enable = true; 44225fdd593SJeykumar Sankaran 44325fdd593SJeykumar Sankaran stage_idx = zpos_cnt[pstate->stage]++; 44425fdd593SJeykumar Sankaran stage_cfg->stage[pstate->stage][stage_idx] = 44525fdd593SJeykumar Sankaran dpu_plane_pipe(plane); 44625fdd593SJeykumar Sankaran stage_cfg->multirect_index[pstate->stage][stage_idx] = 44725fdd593SJeykumar Sankaran pstate->multirect_index; 44825fdd593SJeykumar Sankaran 44925fdd593SJeykumar Sankaran trace_dpu_crtc_setup_mixer(DRMID(crtc), DRMID(plane), 45025fdd593SJeykumar Sankaran state, pstate, stage_idx, 45125fdd593SJeykumar Sankaran dpu_plane_pipe(plane) - SSPP_VIG0, 45225fdd593SJeykumar Sankaran format->base.pixel_format, 45325fdd593SJeykumar Sankaran fb ? fb->modifier : 0); 45425fdd593SJeykumar Sankaran 45525fdd593SJeykumar Sankaran /* blend config update */ 4569222cdd2SJeykumar Sankaran for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) { 45774593a28SSravanthi Kollukuduru _dpu_crtc_setup_blend_cfg(mixer + lm_idx, 45874593a28SSravanthi Kollukuduru pstate, format); 45925fdd593SJeykumar Sankaran 46025fdd593SJeykumar Sankaran mixer[lm_idx].flush_mask |= flush_mask; 46125fdd593SJeykumar Sankaran 46225fdd593SJeykumar Sankaran if (bg_alpha_enable && !format->alpha_enable) 46325fdd593SJeykumar Sankaran mixer[lm_idx].mixer_op_mode = 0; 46425fdd593SJeykumar Sankaran else 46525fdd593SJeykumar Sankaran mixer[lm_idx].mixer_op_mode |= 46625fdd593SJeykumar Sankaran 1 << pstate->stage; 46725fdd593SJeykumar Sankaran } 46825fdd593SJeykumar Sankaran } 46925fdd593SJeykumar Sankaran 470b3652e87SKrishna Manikandan if (ctl->ops.set_active_pipes) 471b3652e87SKrishna Manikandan ctl->ops.set_active_pipes(ctl, fetch_active); 472b3652e87SKrishna Manikandan 47325fdd593SJeykumar Sankaran _dpu_crtc_program_lm_output_roi(crtc); 47425fdd593SJeykumar Sankaran } 47525fdd593SJeykumar Sankaran 47625fdd593SJeykumar Sankaran /** 47725fdd593SJeykumar Sankaran * _dpu_crtc_blend_setup - configure crtc mixers 47825fdd593SJeykumar Sankaran * @crtc: Pointer to drm crtc structure 47925fdd593SJeykumar Sankaran */ 48025fdd593SJeykumar Sankaran static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) 48125fdd593SJeykumar Sankaran { 48204b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 48304b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 48404b96b63SBruce Wang struct dpu_crtc_mixer *mixer = cstate->mixers; 48525fdd593SJeykumar Sankaran struct dpu_hw_ctl *ctl; 48625fdd593SJeykumar Sankaran struct dpu_hw_mixer *lm; 48753c064a1SDmitry Baryshkov struct dpu_hw_stage_cfg stage_cfg; 48825fdd593SJeykumar Sankaran int i; 48925fdd593SJeykumar Sankaran 4905b702d78SStephen Boyd DRM_DEBUG_ATOMIC("%s\n", dpu_crtc->name); 49125fdd593SJeykumar Sankaran 4929222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; i++) { 49325fdd593SJeykumar Sankaran mixer[i].mixer_op_mode = 0; 49425fdd593SJeykumar Sankaran mixer[i].flush_mask = 0; 495cf6916f4SJeykumar Sankaran if (mixer[i].lm_ctl->ops.clear_all_blendstages) 496cf6916f4SJeykumar Sankaran mixer[i].lm_ctl->ops.clear_all_blendstages( 497cf6916f4SJeykumar Sankaran mixer[i].lm_ctl); 49825fdd593SJeykumar Sankaran } 49925fdd593SJeykumar Sankaran 50025fdd593SJeykumar Sankaran /* initialize stage cfg */ 50153c064a1SDmitry Baryshkov memset(&stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg)); 50225fdd593SJeykumar Sankaran 50353c064a1SDmitry Baryshkov _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, &stage_cfg); 50425fdd593SJeykumar Sankaran 5059222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; i++) { 506cf6916f4SJeykumar Sankaran ctl = mixer[i].lm_ctl; 50725fdd593SJeykumar Sankaran lm = mixer[i].hw_lm; 50825fdd593SJeykumar Sankaran 50925fdd593SJeykumar Sankaran lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); 51025fdd593SJeykumar Sankaran 51125fdd593SJeykumar Sankaran mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl, 51225fdd593SJeykumar Sankaran mixer[i].hw_lm->idx); 51325fdd593SJeykumar Sankaran 51425fdd593SJeykumar Sankaran /* stage config flush mask */ 51525fdd593SJeykumar Sankaran ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); 51625fdd593SJeykumar Sankaran 5175b702d78SStephen Boyd DRM_DEBUG_ATOMIC("lm %d, op_mode 0x%X, ctl %d, flush mask 0x%x\n", 51825fdd593SJeykumar Sankaran mixer[i].hw_lm->idx - LM_0, 51925fdd593SJeykumar Sankaran mixer[i].mixer_op_mode, 52025fdd593SJeykumar Sankaran ctl->idx - CTL_0, 52125fdd593SJeykumar Sankaran mixer[i].flush_mask); 52225fdd593SJeykumar Sankaran 52325fdd593SJeykumar Sankaran ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, 52453c064a1SDmitry Baryshkov &stage_cfg); 52525fdd593SJeykumar Sankaran } 52625fdd593SJeykumar Sankaran } 52725fdd593SJeykumar Sankaran 52825fdd593SJeykumar Sankaran /** 52925fdd593SJeykumar Sankaran * _dpu_crtc_complete_flip - signal pending page_flip events 53025fdd593SJeykumar Sankaran * Any pending vblank events are added to the vblank_event_list 53125fdd593SJeykumar Sankaran * so that the next vblank interrupt shall signal them. 53225fdd593SJeykumar Sankaran * However PAGE_FLIP events are not handled through the vblank_event_list. 53325fdd593SJeykumar Sankaran * This API signals any pending PAGE_FLIP events requested through 53425fdd593SJeykumar Sankaran * DRM_IOCTL_MODE_PAGE_FLIP and are cached in the dpu_crtc->event. 53525fdd593SJeykumar Sankaran * @crtc: Pointer to drm crtc structure 53625fdd593SJeykumar Sankaran */ 53725fdd593SJeykumar Sankaran static void _dpu_crtc_complete_flip(struct drm_crtc *crtc) 53825fdd593SJeykumar Sankaran { 53925fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 54025fdd593SJeykumar Sankaran struct drm_device *dev = crtc->dev; 54125fdd593SJeykumar Sankaran unsigned long flags; 54225fdd593SJeykumar Sankaran 54325fdd593SJeykumar Sankaran spin_lock_irqsave(&dev->event_lock, flags); 54425fdd593SJeykumar Sankaran if (dpu_crtc->event) { 54525fdd593SJeykumar Sankaran DRM_DEBUG_VBL("%s: send event: %pK\n", dpu_crtc->name, 54625fdd593SJeykumar Sankaran dpu_crtc->event); 54725fdd593SJeykumar Sankaran trace_dpu_crtc_complete_flip(DRMID(crtc)); 54825fdd593SJeykumar Sankaran drm_crtc_send_vblank_event(crtc, dpu_crtc->event); 54925fdd593SJeykumar Sankaran dpu_crtc->event = NULL; 55025fdd593SJeykumar Sankaran } 55125fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dev->event_lock, flags); 55225fdd593SJeykumar Sankaran } 55325fdd593SJeykumar Sankaran 55425fdd593SJeykumar Sankaran enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) 55525fdd593SJeykumar Sankaran { 55625fdd593SJeykumar Sankaran struct drm_encoder *encoder; 55725fdd593SJeykumar Sankaran 558ab198a7aSSean Paul /* 559ab198a7aSSean Paul * TODO: This function is called from dpu debugfs and as part of atomic 560ab198a7aSSean Paul * check. When called from debugfs, the crtc->mutex must be held to 561ab198a7aSSean Paul * read crtc->state. However reading crtc->state from atomic check isn't 562ab198a7aSSean Paul * allowed (unless you have a good reason, a big comment, and a deep 563ab198a7aSSean Paul * understanding of how the atomic/modeset locks work (<- and this is 564ab198a7aSSean Paul * probably not possible)). So we'll keep the WARN_ON here for now, but 565ab198a7aSSean Paul * really we need to figure out a better way to track our operating mode 566ab198a7aSSean Paul */ 5671dfdb0e1SSean Paul WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 5681dfdb0e1SSean Paul 5694b8c6279SSean Paul /* TODO: Returns the first INTF_MODE, could there be multiple values? */ 5704b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 57125fdd593SJeykumar Sankaran return dpu_encoder_get_intf_mode(encoder); 57225fdd593SJeykumar Sankaran 57325fdd593SJeykumar Sankaran return INTF_MODE_NONE; 57425fdd593SJeykumar Sankaran } 57525fdd593SJeykumar Sankaran 576e4914867SSean Paul void dpu_crtc_vblank_callback(struct drm_crtc *crtc) 57725fdd593SJeykumar Sankaran { 57825fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 57925fdd593SJeykumar Sankaran 58025fdd593SJeykumar Sankaran /* keep statistics on vblank callback - with auto reset via debugfs */ 58125fdd593SJeykumar Sankaran if (ktime_compare(dpu_crtc->vblank_cb_time, ktime_set(0, 0)) == 0) 58225fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_time = ktime_get(); 58325fdd593SJeykumar Sankaran else 58425fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_count++; 58578d9b458SJessica Zhang 58678d9b458SJessica Zhang dpu_crtc_get_crc(crtc); 58778d9b458SJessica Zhang 58825fdd593SJeykumar Sankaran drm_crtc_handle_vblank(crtc); 58925fdd593SJeykumar Sankaran trace_dpu_crtc_vblank_cb(DRMID(crtc)); 59025fdd593SJeykumar Sankaran } 59125fdd593SJeykumar Sankaran 59225fdd593SJeykumar Sankaran static void dpu_crtc_frame_event_work(struct kthread_work *work) 59325fdd593SJeykumar Sankaran { 59404b96b63SBruce Wang struct dpu_crtc_frame_event *fevent = container_of(work, 59504b96b63SBruce Wang struct dpu_crtc_frame_event, work); 59604b96b63SBruce Wang struct drm_crtc *crtc = fevent->crtc; 59704b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 59825fdd593SJeykumar Sankaran unsigned long flags; 59925fdd593SJeykumar Sankaran bool frame_done = false; 60025fdd593SJeykumar Sankaran 60125fdd593SJeykumar Sankaran DPU_ATRACE_BEGIN("crtc_frame_event"); 60225fdd593SJeykumar Sankaran 6035b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event, 60425fdd593SJeykumar Sankaran ktime_to_ns(fevent->ts)); 60525fdd593SJeykumar Sankaran 60625fdd593SJeykumar Sankaran if (fevent->event & (DPU_ENCODER_FRAME_EVENT_DONE 60725fdd593SJeykumar Sankaran | DPU_ENCODER_FRAME_EVENT_ERROR 60825fdd593SJeykumar Sankaran | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { 60925fdd593SJeykumar Sankaran 61025fdd593SJeykumar Sankaran if (atomic_read(&dpu_crtc->frame_pending) < 1) { 61141a52059SRob Clark /* ignore vblank when not pending */ 61225fdd593SJeykumar Sankaran } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { 61325fdd593SJeykumar Sankaran /* release bandwidth and other resources */ 61425fdd593SJeykumar Sankaran trace_dpu_crtc_frame_event_done(DRMID(crtc), 61525fdd593SJeykumar Sankaran fevent->event); 616241b507cSRob Clark dpu_core_perf_crtc_release_bw(crtc); 61725fdd593SJeykumar Sankaran } else { 61825fdd593SJeykumar Sankaran trace_dpu_crtc_frame_event_more_pending(DRMID(crtc), 61925fdd593SJeykumar Sankaran fevent->event); 62025fdd593SJeykumar Sankaran } 62125fdd593SJeykumar Sankaran 62225fdd593SJeykumar Sankaran if (fevent->event & (DPU_ENCODER_FRAME_EVENT_DONE 62325fdd593SJeykumar Sankaran | DPU_ENCODER_FRAME_EVENT_ERROR)) 62425fdd593SJeykumar Sankaran frame_done = true; 62525fdd593SJeykumar Sankaran } 62625fdd593SJeykumar Sankaran 62725fdd593SJeykumar Sankaran if (fevent->event & DPU_ENCODER_FRAME_EVENT_PANEL_DEAD) 62825fdd593SJeykumar Sankaran DPU_ERROR("crtc%d ts:%lld received panel dead event\n", 62925fdd593SJeykumar Sankaran crtc->base.id, ktime_to_ns(fevent->ts)); 63025fdd593SJeykumar Sankaran 63125fdd593SJeykumar Sankaran if (frame_done) 63225fdd593SJeykumar Sankaran complete_all(&dpu_crtc->frame_done_comp); 63325fdd593SJeykumar Sankaran 63425fdd593SJeykumar Sankaran spin_lock_irqsave(&dpu_crtc->spin_lock, flags); 63525fdd593SJeykumar Sankaran list_add_tail(&fevent->list, &dpu_crtc->frame_event_list); 63625fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags); 63725fdd593SJeykumar Sankaran DPU_ATRACE_END("crtc_frame_event"); 63825fdd593SJeykumar Sankaran } 63925fdd593SJeykumar Sankaran 64025fdd593SJeykumar Sankaran /* 64125fdd593SJeykumar Sankaran * dpu_crtc_frame_event_cb - crtc frame event callback API. CRTC module 64225fdd593SJeykumar Sankaran * registers this API to encoder for all frame event callbacks like 64325fdd593SJeykumar Sankaran * frame_error, frame_done, idle_timeout, etc. Encoder may call different events 64425fdd593SJeykumar Sankaran * from different context - IRQ, user thread, commit_thread, etc. Each event 64525fdd593SJeykumar Sankaran * should be carefully reviewed and should be processed in proper task context 64625fdd593SJeykumar Sankaran * to avoid schedulin delay or properly manage the irq context's bottom half 64725fdd593SJeykumar Sankaran * processing. 64825fdd593SJeykumar Sankaran */ 64925fdd593SJeykumar Sankaran static void dpu_crtc_frame_event_cb(void *data, u32 event) 65025fdd593SJeykumar Sankaran { 65125fdd593SJeykumar Sankaran struct drm_crtc *crtc = (struct drm_crtc *)data; 65225fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc; 65325fdd593SJeykumar Sankaran struct msm_drm_private *priv; 65425fdd593SJeykumar Sankaran struct dpu_crtc_frame_event *fevent; 65525fdd593SJeykumar Sankaran unsigned long flags; 65625fdd593SJeykumar Sankaran u32 crtc_id; 65725fdd593SJeykumar Sankaran 65825fdd593SJeykumar Sankaran /* Nothing to do on idle event */ 65925fdd593SJeykumar Sankaran if (event & DPU_ENCODER_FRAME_EVENT_IDLE) 66025fdd593SJeykumar Sankaran return; 66125fdd593SJeykumar Sankaran 66225fdd593SJeykumar Sankaran dpu_crtc = to_dpu_crtc(crtc); 66325fdd593SJeykumar Sankaran priv = crtc->dev->dev_private; 66425fdd593SJeykumar Sankaran crtc_id = drm_crtc_index(crtc); 66525fdd593SJeykumar Sankaran 66625fdd593SJeykumar Sankaran trace_dpu_crtc_frame_event_cb(DRMID(crtc), event); 66725fdd593SJeykumar Sankaran 66825fdd593SJeykumar Sankaran spin_lock_irqsave(&dpu_crtc->spin_lock, flags); 66925fdd593SJeykumar Sankaran fevent = list_first_entry_or_null(&dpu_crtc->frame_event_list, 67025fdd593SJeykumar Sankaran struct dpu_crtc_frame_event, list); 67125fdd593SJeykumar Sankaran if (fevent) 67225fdd593SJeykumar Sankaran list_del_init(&fevent->list); 67325fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags); 67425fdd593SJeykumar Sankaran 67525fdd593SJeykumar Sankaran if (!fevent) { 6765e16372bSRob Clark DRM_ERROR_RATELIMITED("crtc%d event %d overflow\n", crtc->base.id, event); 67725fdd593SJeykumar Sankaran return; 67825fdd593SJeykumar Sankaran } 67925fdd593SJeykumar Sankaran 68025fdd593SJeykumar Sankaran fevent->event = event; 68125fdd593SJeykumar Sankaran fevent->crtc = crtc; 68225fdd593SJeykumar Sankaran fevent->ts = ktime_get(); 6831041dee2SBernard kthread_queue_work(priv->event_thread[crtc_id].worker, &fevent->work); 68425fdd593SJeykumar Sankaran } 68525fdd593SJeykumar Sankaran 68680b4b4a7SRob Clark void dpu_crtc_complete_commit(struct drm_crtc *crtc) 68725fdd593SJeykumar Sankaran { 68825fdd593SJeykumar Sankaran trace_dpu_crtc_complete_commit(DRMID(crtc)); 689a1f2ba60SKrishna Manikandan dpu_core_perf_crtc_update(crtc, 0, false); 690fd630ae9SRob Clark _dpu_crtc_complete_flip(crtc); 69125fdd593SJeykumar Sankaran } 69225fdd593SJeykumar Sankaran 69325fdd593SJeykumar Sankaran static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, 69425fdd593SJeykumar Sankaran struct drm_crtc_state *state) 69525fdd593SJeykumar Sankaran { 69604b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); 69704b96b63SBruce Wang struct drm_display_mode *adj_mode = &state->adjusted_mode; 6983804a982SJordan Crouse u32 crtc_split_width = adj_mode->hdisplay / cstate->num_mixers; 69925fdd593SJeykumar Sankaran int i; 70025fdd593SJeykumar Sankaran 7019222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; i++) { 70225fdd593SJeykumar Sankaran struct drm_rect *r = &cstate->lm_bounds[i]; 70325fdd593SJeykumar Sankaran r->x1 = crtc_split_width * i; 70425fdd593SJeykumar Sankaran r->y1 = 0; 70525fdd593SJeykumar Sankaran r->x2 = r->x1 + crtc_split_width; 70635d600ddSJordan Crouse r->y2 = adj_mode->vdisplay; 70725fdd593SJeykumar Sankaran 70825fdd593SJeykumar Sankaran trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r); 70925fdd593SJeykumar Sankaran } 71025fdd593SJeykumar Sankaran } 71125fdd593SJeykumar Sankaran 7124259ff7aSKalyan Thota static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, 7134259ff7aSKalyan Thota struct dpu_hw_pcc_cfg *cfg) 7144259ff7aSKalyan Thota { 7154259ff7aSKalyan Thota struct drm_color_ctm *ctm; 7164259ff7aSKalyan Thota 7174259ff7aSKalyan Thota memset(cfg, 0, sizeof(struct dpu_hw_pcc_cfg)); 7184259ff7aSKalyan Thota 7194259ff7aSKalyan Thota ctm = (struct drm_color_ctm *)state->ctm->data; 7204259ff7aSKalyan Thota 7214259ff7aSKalyan Thota if (!ctm) 7224259ff7aSKalyan Thota return; 7234259ff7aSKalyan Thota 7244259ff7aSKalyan Thota cfg->r.r = CONVERT_S3_15(ctm->matrix[0]); 7254259ff7aSKalyan Thota cfg->g.r = CONVERT_S3_15(ctm->matrix[1]); 7264259ff7aSKalyan Thota cfg->b.r = CONVERT_S3_15(ctm->matrix[2]); 7274259ff7aSKalyan Thota 7284259ff7aSKalyan Thota cfg->r.g = CONVERT_S3_15(ctm->matrix[3]); 7294259ff7aSKalyan Thota cfg->g.g = CONVERT_S3_15(ctm->matrix[4]); 7304259ff7aSKalyan Thota cfg->b.g = CONVERT_S3_15(ctm->matrix[5]); 7314259ff7aSKalyan Thota 7324259ff7aSKalyan Thota cfg->r.b = CONVERT_S3_15(ctm->matrix[6]); 7334259ff7aSKalyan Thota cfg->g.b = CONVERT_S3_15(ctm->matrix[7]); 7344259ff7aSKalyan Thota cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); 7354259ff7aSKalyan Thota } 7364259ff7aSKalyan Thota 7374259ff7aSKalyan Thota static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) 7384259ff7aSKalyan Thota { 7394259ff7aSKalyan Thota struct drm_crtc_state *state = crtc->state; 7404259ff7aSKalyan Thota struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 7414259ff7aSKalyan Thota struct dpu_crtc_mixer *mixer = cstate->mixers; 7424259ff7aSKalyan Thota struct dpu_hw_pcc_cfg cfg; 7434259ff7aSKalyan Thota struct dpu_hw_ctl *ctl; 7444259ff7aSKalyan Thota struct dpu_hw_dspp *dspp; 7454259ff7aSKalyan Thota int i; 7464259ff7aSKalyan Thota 7474259ff7aSKalyan Thota 7484259ff7aSKalyan Thota if (!state->color_mgmt_changed) 7494259ff7aSKalyan Thota return; 7504259ff7aSKalyan Thota 7514259ff7aSKalyan Thota for (i = 0; i < cstate->num_mixers; i++) { 7524259ff7aSKalyan Thota ctl = mixer[i].lm_ctl; 7534259ff7aSKalyan Thota dspp = mixer[i].hw_dspp; 7544259ff7aSKalyan Thota 7554259ff7aSKalyan Thota if (!dspp || !dspp->ops.setup_pcc) 7564259ff7aSKalyan Thota continue; 7574259ff7aSKalyan Thota 7584259ff7aSKalyan Thota if (!state->ctm) { 7594259ff7aSKalyan Thota dspp->ops.setup_pcc(dspp, NULL); 7604259ff7aSKalyan Thota } else { 7614259ff7aSKalyan Thota _dpu_crtc_get_pcc_coeff(state, &cfg); 7624259ff7aSKalyan Thota dspp->ops.setup_pcc(dspp, &cfg); 7634259ff7aSKalyan Thota } 7644259ff7aSKalyan Thota 7654259ff7aSKalyan Thota mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, 7664259ff7aSKalyan Thota mixer[i].hw_dspp->idx); 7674259ff7aSKalyan Thota 7684259ff7aSKalyan Thota /* stage config flush mask */ 7694259ff7aSKalyan Thota ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); 7704259ff7aSKalyan Thota 7715b702d78SStephen Boyd DRM_DEBUG_ATOMIC("lm %d, ctl %d, flush mask 0x%x\n", 7724259ff7aSKalyan Thota mixer[i].hw_lm->idx - DSPP_0, 7734259ff7aSKalyan Thota ctl->idx - CTL_0, 7744259ff7aSKalyan Thota mixer[i].flush_mask); 7754259ff7aSKalyan Thota } 7764259ff7aSKalyan Thota } 7774259ff7aSKalyan Thota 77825fdd593SJeykumar Sankaran static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, 779f6ebe9f9SMaxime Ripard struct drm_atomic_state *state) 78025fdd593SJeykumar Sankaran { 781e12e5263SRob Clark struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 78225fdd593SJeykumar Sankaran struct drm_encoder *encoder; 78325fdd593SJeykumar Sankaran 78425fdd593SJeykumar Sankaran if (!crtc->state->enable) { 7855b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d -> enable %d, skip atomic_begin\n", 78625fdd593SJeykumar Sankaran crtc->base.id, crtc->state->enable); 78725fdd593SJeykumar Sankaran return; 78825fdd593SJeykumar Sankaran } 78925fdd593SJeykumar Sankaran 7905b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d\n", crtc->base.id); 79125fdd593SJeykumar Sankaran 79225fdd593SJeykumar Sankaran _dpu_crtc_setup_lm_bounds(crtc, crtc->state); 79325fdd593SJeykumar Sankaran 79425fdd593SJeykumar Sankaran /* encoder will trigger pending mask now */ 7954b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 79625fdd593SJeykumar Sankaran dpu_encoder_trigger_kickoff_pending(encoder); 79725fdd593SJeykumar Sankaran 79825fdd593SJeykumar Sankaran /* 79925fdd593SJeykumar Sankaran * If no mixers have been allocated in dpu_crtc_atomic_check(), 80025fdd593SJeykumar Sankaran * it means we are trying to flush a CRTC whose state is disabled: 80125fdd593SJeykumar Sankaran * nothing else needs to be done. 80225fdd593SJeykumar Sankaran */ 8039222cdd2SJeykumar Sankaran if (unlikely(!cstate->num_mixers)) 80425fdd593SJeykumar Sankaran return; 80525fdd593SJeykumar Sankaran 80625fdd593SJeykumar Sankaran _dpu_crtc_blend_setup(crtc); 80725fdd593SJeykumar Sankaran 8084259ff7aSKalyan Thota _dpu_crtc_setup_cp_blocks(crtc); 8094259ff7aSKalyan Thota 81025fdd593SJeykumar Sankaran /* 81125fdd593SJeykumar Sankaran * PP_DONE irq is only used by command mode for now. 81225fdd593SJeykumar Sankaran * It is better to request pending before FLUSH and START trigger 81325fdd593SJeykumar Sankaran * to make sure no pp_done irq missed. 81425fdd593SJeykumar Sankaran * This is safe because no pp_done will happen before SW trigger 81525fdd593SJeykumar Sankaran * in command mode. 81625fdd593SJeykumar Sankaran */ 81725fdd593SJeykumar Sankaran } 81825fdd593SJeykumar Sankaran 81925fdd593SJeykumar Sankaran static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, 820f6ebe9f9SMaxime Ripard struct drm_atomic_state *state) 82125fdd593SJeykumar Sankaran { 82225fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc; 82325fdd593SJeykumar Sankaran struct drm_device *dev; 82425fdd593SJeykumar Sankaran struct drm_plane *plane; 82525fdd593SJeykumar Sankaran struct msm_drm_private *priv; 82625fdd593SJeykumar Sankaran unsigned long flags; 82725fdd593SJeykumar Sankaran struct dpu_crtc_state *cstate; 82825fdd593SJeykumar Sankaran 82925fdd593SJeykumar Sankaran if (!crtc->state->enable) { 8305b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d -> enable %d, skip atomic_flush\n", 83125fdd593SJeykumar Sankaran crtc->base.id, crtc->state->enable); 83225fdd593SJeykumar Sankaran return; 83325fdd593SJeykumar Sankaran } 83425fdd593SJeykumar Sankaran 8355b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d\n", crtc->base.id); 83625fdd593SJeykumar Sankaran 83725fdd593SJeykumar Sankaran dpu_crtc = to_dpu_crtc(crtc); 83825fdd593SJeykumar Sankaran cstate = to_dpu_crtc_state(crtc->state); 83925fdd593SJeykumar Sankaran dev = crtc->dev; 84025fdd593SJeykumar Sankaran priv = dev->dev_private; 84125fdd593SJeykumar Sankaran 84225fdd593SJeykumar Sankaran if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { 84325fdd593SJeykumar Sankaran DPU_ERROR("invalid crtc index[%d]\n", crtc->index); 84425fdd593SJeykumar Sankaran return; 84525fdd593SJeykumar Sankaran } 84625fdd593SJeykumar Sankaran 847e12e5263SRob Clark WARN_ON(dpu_crtc->event); 84825fdd593SJeykumar Sankaran spin_lock_irqsave(&dev->event_lock, flags); 84925fdd593SJeykumar Sankaran dpu_crtc->event = crtc->state->event; 85025fdd593SJeykumar Sankaran crtc->state->event = NULL; 85125fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dev->event_lock, flags); 85225fdd593SJeykumar Sankaran 85325fdd593SJeykumar Sankaran /* 85425fdd593SJeykumar Sankaran * If no mixers has been allocated in dpu_crtc_atomic_check(), 85525fdd593SJeykumar Sankaran * it means we are trying to flush a CRTC whose state is disabled: 85625fdd593SJeykumar Sankaran * nothing else needs to be done. 85725fdd593SJeykumar Sankaran */ 8589222cdd2SJeykumar Sankaran if (unlikely(!cstate->num_mixers)) 85925fdd593SJeykumar Sankaran return; 86025fdd593SJeykumar Sankaran 86125fdd593SJeykumar Sankaran /* update performance setting before crtc kickoff */ 86225fdd593SJeykumar Sankaran dpu_core_perf_crtc_update(crtc, 1, false); 86325fdd593SJeykumar Sankaran 86425fdd593SJeykumar Sankaran /* 86525fdd593SJeykumar Sankaran * Final plane updates: Give each plane a chance to complete all 86625fdd593SJeykumar Sankaran * required writes/flushing before crtc's "flush 86725fdd593SJeykumar Sankaran * everything" call below. 86825fdd593SJeykumar Sankaran */ 86925fdd593SJeykumar Sankaran drm_atomic_crtc_for_each_plane(plane, crtc) { 87025fdd593SJeykumar Sankaran if (dpu_crtc->smmu_state.transition_error) 87125fdd593SJeykumar Sankaran dpu_plane_set_error(plane, true); 87225fdd593SJeykumar Sankaran dpu_plane_flush(plane); 87325fdd593SJeykumar Sankaran } 87425fdd593SJeykumar Sankaran 87525fdd593SJeykumar Sankaran /* Kickoff will be scheduled by outer layer */ 87625fdd593SJeykumar Sankaran } 87725fdd593SJeykumar Sankaran 87825fdd593SJeykumar Sankaran /** 87925fdd593SJeykumar Sankaran * dpu_crtc_destroy_state - state destroy hook 88025fdd593SJeykumar Sankaran * @crtc: drm CRTC 88125fdd593SJeykumar Sankaran * @state: CRTC state object to release 88225fdd593SJeykumar Sankaran */ 88325fdd593SJeykumar Sankaran static void dpu_crtc_destroy_state(struct drm_crtc *crtc, 88425fdd593SJeykumar Sankaran struct drm_crtc_state *state) 88525fdd593SJeykumar Sankaran { 886e12e5263SRob Clark struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); 88725fdd593SJeykumar Sankaran 8885b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d\n", crtc->base.id); 88925fdd593SJeykumar Sankaran 89025fdd593SJeykumar Sankaran __drm_atomic_helper_crtc_destroy_state(state); 89125fdd593SJeykumar Sankaran 89225fdd593SJeykumar Sankaran kfree(cstate); 89325fdd593SJeykumar Sankaran } 89425fdd593SJeykumar Sankaran 89525fdd593SJeykumar Sankaran static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) 89625fdd593SJeykumar Sankaran { 89704b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 89825fdd593SJeykumar Sankaran int ret, rc = 0; 89925fdd593SJeykumar Sankaran 90025fdd593SJeykumar Sankaran if (!atomic_read(&dpu_crtc->frame_pending)) { 9015b702d78SStephen Boyd DRM_DEBUG_ATOMIC("no frames pending\n"); 90225fdd593SJeykumar Sankaran return 0; 90325fdd593SJeykumar Sankaran } 90425fdd593SJeykumar Sankaran 90525fdd593SJeykumar Sankaran DPU_ATRACE_BEGIN("frame done completion wait"); 90625fdd593SJeykumar Sankaran ret = wait_for_completion_timeout(&dpu_crtc->frame_done_comp, 90770df9610SSean Paul msecs_to_jiffies(DPU_CRTC_FRAME_DONE_TIMEOUT_MS)); 90825fdd593SJeykumar Sankaran if (!ret) { 90925fdd593SJeykumar Sankaran DRM_ERROR("frame done wait timed out, ret:%d\n", ret); 91025fdd593SJeykumar Sankaran rc = -ETIMEDOUT; 91125fdd593SJeykumar Sankaran } 91225fdd593SJeykumar Sankaran DPU_ATRACE_END("frame done completion wait"); 91325fdd593SJeykumar Sankaran 91425fdd593SJeykumar Sankaran return rc; 91525fdd593SJeykumar Sankaran } 91625fdd593SJeykumar Sankaran 917b4bb9f15SRob Clark void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) 91825fdd593SJeykumar Sankaran { 91925fdd593SJeykumar Sankaran struct drm_encoder *encoder; 92004b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 92104b96b63SBruce Wang struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); 92204b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 92325fdd593SJeykumar Sankaran 92425fdd593SJeykumar Sankaran /* 92525fdd593SJeykumar Sankaran * If no mixers has been allocated in dpu_crtc_atomic_check(), 92625fdd593SJeykumar Sankaran * it means we are trying to start a CRTC whose state is disabled: 92725fdd593SJeykumar Sankaran * nothing else needs to be done. 92825fdd593SJeykumar Sankaran */ 9299222cdd2SJeykumar Sankaran if (unlikely(!cstate->num_mixers)) 93025fdd593SJeykumar Sankaran return; 93125fdd593SJeykumar Sankaran 93225fdd593SJeykumar Sankaran DPU_ATRACE_BEGIN("crtc_commit"); 93325fdd593SJeykumar Sankaran 934f2969c49SAbhinav Kumar drm_for_each_encoder_mask(encoder, crtc->dev, 935f2969c49SAbhinav Kumar crtc->state->encoder_mask) { 936f2969c49SAbhinav Kumar if (!dpu_encoder_is_valid_for_commit(encoder)) { 937f2969c49SAbhinav Kumar DRM_DEBUG_ATOMIC("invalid FB not kicking off crtc\n"); 938f2969c49SAbhinav Kumar goto end; 939f2969c49SAbhinav Kumar } 940f2969c49SAbhinav Kumar } 94125fdd593SJeykumar Sankaran /* 9424b8c6279SSean Paul * Encoder will flush/start now, unless it has a tx pending. If so, it 9434b8c6279SSean Paul * may delay and flush at an irq event (e.g. ppdone) 94425fdd593SJeykumar Sankaran */ 9454b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, 946d3db61caSBruce Wang crtc->state->encoder_mask) 9470c91ed51SRob Clark dpu_encoder_prepare_for_kickoff(encoder); 94850bcc689SSean Paul 94925fdd593SJeykumar Sankaran if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { 95025fdd593SJeykumar Sankaran /* acquire bandwidth and other resources */ 9515b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d first commit\n", crtc->base.id); 95225fdd593SJeykumar Sankaran } else 9535b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d commit\n", crtc->base.id); 95425fdd593SJeykumar Sankaran 95525fdd593SJeykumar Sankaran dpu_crtc->play_count++; 95625fdd593SJeykumar Sankaran 95725fdd593SJeykumar Sankaran dpu_vbif_clear_errors(dpu_kms); 95825fdd593SJeykumar Sankaran 9594b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 960b4bb9f15SRob Clark dpu_encoder_kickoff(encoder); 96125fdd593SJeykumar Sankaran 96225fdd593SJeykumar Sankaran reinit_completion(&dpu_crtc->frame_done_comp); 963f2969c49SAbhinav Kumar 964f2969c49SAbhinav Kumar end: 96525fdd593SJeykumar Sankaran DPU_ATRACE_END("crtc_commit"); 96625fdd593SJeykumar Sankaran } 96725fdd593SJeykumar Sankaran 968ff5952a7SSean Paul static void dpu_crtc_reset(struct drm_crtc *crtc) 96925fdd593SJeykumar Sankaran { 9701cff7440SMaarten Lankhorst struct dpu_crtc_state *cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); 97125fdd593SJeykumar Sankaran 972ff5952a7SSean Paul if (crtc->state) 973ff5952a7SSean Paul dpu_crtc_destroy_state(crtc, crtc->state); 97425fdd593SJeykumar Sankaran 9751cff7440SMaarten Lankhorst __drm_atomic_helper_crtc_reset(crtc, &cstate->base); 97625fdd593SJeykumar Sankaran } 97725fdd593SJeykumar Sankaran 97825fdd593SJeykumar Sankaran /** 97925fdd593SJeykumar Sankaran * dpu_crtc_duplicate_state - state duplicate hook 98025fdd593SJeykumar Sankaran * @crtc: Pointer to drm crtc structure 98125fdd593SJeykumar Sankaran */ 98225fdd593SJeykumar Sankaran static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) 98325fdd593SJeykumar Sankaran { 984e12e5263SRob Clark struct dpu_crtc_state *cstate, *old_cstate = to_dpu_crtc_state(crtc->state); 98525fdd593SJeykumar Sankaran 98625fdd593SJeykumar Sankaran cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); 98725fdd593SJeykumar Sankaran if (!cstate) { 98825fdd593SJeykumar Sankaran DPU_ERROR("failed to allocate state\n"); 98925fdd593SJeykumar Sankaran return NULL; 99025fdd593SJeykumar Sankaran } 99125fdd593SJeykumar Sankaran 99225fdd593SJeykumar Sankaran /* duplicate base helper */ 99325fdd593SJeykumar Sankaran __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); 99425fdd593SJeykumar Sankaran 99525fdd593SJeykumar Sankaran return &cstate->base; 99625fdd593SJeykumar Sankaran } 99725fdd593SJeykumar Sankaran 99853b53337SDmitry Baryshkov static void dpu_crtc_atomic_print_state(struct drm_printer *p, 99953b53337SDmitry Baryshkov const struct drm_crtc_state *state) 100053b53337SDmitry Baryshkov { 100153b53337SDmitry Baryshkov const struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); 100253b53337SDmitry Baryshkov int i; 100353b53337SDmitry Baryshkov 100453b53337SDmitry Baryshkov for (i = 0; i < cstate->num_mixers; i++) { 100553b53337SDmitry Baryshkov drm_printf(p, "\tlm[%d]=%d\n", i, cstate->mixers[i].hw_lm->idx - LM_0); 100653b53337SDmitry Baryshkov drm_printf(p, "\tctl[%d]=%d\n", i, cstate->mixers[i].lm_ctl->idx - CTL_0); 100753b53337SDmitry Baryshkov if (cstate->mixers[i].hw_dspp) 100853b53337SDmitry Baryshkov drm_printf(p, "\tdspp[%d]=%d\n", i, cstate->mixers[i].hw_dspp->idx - DSPP_0); 100953b53337SDmitry Baryshkov } 101053b53337SDmitry Baryshkov } 101153b53337SDmitry Baryshkov 1012f7aafc8dSSean Paul static void dpu_crtc_disable(struct drm_crtc *crtc, 1013351f950dSMaxime Ripard struct drm_atomic_state *state) 101425fdd593SJeykumar Sankaran { 1015351f950dSMaxime Ripard struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, 1016351f950dSMaxime Ripard crtc); 1017e12e5263SRob Clark struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 1018e12e5263SRob Clark struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 101925fdd593SJeykumar Sankaran struct drm_encoder *encoder; 10202f2eb723SRajesh Yadav unsigned long flags; 1021241b507cSRob Clark bool release_bandwidth = false; 102225fdd593SJeykumar Sankaran 102325fdd593SJeykumar Sankaran DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); 102425fdd593SJeykumar Sankaran 10252f2eb723SRajesh Yadav /* Disable/save vblank irq handling */ 10262f2eb723SRajesh Yadav drm_crtc_vblank_off(crtc); 10272f2eb723SRajesh Yadav 1028a796ba2cSSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, 1029241b507cSRob Clark old_crtc_state->encoder_mask) { 1030241b507cSRob Clark /* in video mode, we hold an extra bandwidth reference 1031241b507cSRob Clark * as we cannot drop bandwidth at frame-done if any 1032241b507cSRob Clark * crtc is being used in video mode. 1033241b507cSRob Clark */ 1034241b507cSRob Clark if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) 1035241b507cSRob Clark release_bandwidth = true; 1036a796ba2cSSean Paul dpu_encoder_assign_crtc(encoder, NULL); 1037241b507cSRob Clark } 103825fdd593SJeykumar Sankaran 103925fdd593SJeykumar Sankaran /* wait for frame_event_done completion */ 104025fdd593SJeykumar Sankaran if (_dpu_crtc_wait_for_frame_done(crtc)) 104125fdd593SJeykumar Sankaran DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", 104225fdd593SJeykumar Sankaran crtc->base.id, 104325fdd593SJeykumar Sankaran atomic_read(&dpu_crtc->frame_pending)); 104425fdd593SJeykumar Sankaran 104525fdd593SJeykumar Sankaran trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); 104625fdd593SJeykumar Sankaran dpu_crtc->enabled = false; 104725fdd593SJeykumar Sankaran 104825fdd593SJeykumar Sankaran if (atomic_read(&dpu_crtc->frame_pending)) { 104925fdd593SJeykumar Sankaran trace_dpu_crtc_disable_frame_pending(DRMID(crtc), 105025fdd593SJeykumar Sankaran atomic_read(&dpu_crtc->frame_pending)); 1051241b507cSRob Clark if (release_bandwidth) 105225fdd593SJeykumar Sankaran dpu_core_perf_crtc_release_bw(crtc); 105325fdd593SJeykumar Sankaran atomic_set(&dpu_crtc->frame_pending, 0); 105425fdd593SJeykumar Sankaran } 105525fdd593SJeykumar Sankaran 105625fdd593SJeykumar Sankaran dpu_core_perf_crtc_update(crtc, 0, true); 105725fdd593SJeykumar Sankaran 10584b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 105925fdd593SJeykumar Sankaran dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); 106025fdd593SJeykumar Sankaran 10619222cdd2SJeykumar Sankaran memset(cstate->mixers, 0, sizeof(cstate->mixers)); 10629222cdd2SJeykumar Sankaran cstate->num_mixers = 0; 106325fdd593SJeykumar Sankaran 106425fdd593SJeykumar Sankaran /* disable clk & bw control until clk & bw properties are set */ 106525fdd593SJeykumar Sankaran cstate->bw_control = false; 106625fdd593SJeykumar Sankaran cstate->bw_split_vote = false; 106725fdd593SJeykumar Sankaran 10682f2eb723SRajesh Yadav if (crtc->state->event && !crtc->state->active) { 10692f2eb723SRajesh Yadav spin_lock_irqsave(&crtc->dev->event_lock, flags); 10702f2eb723SRajesh Yadav drm_crtc_send_vblank_event(crtc, crtc->state->event); 10712f2eb723SRajesh Yadav crtc->state->event = NULL; 10722f2eb723SRajesh Yadav spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 10732f2eb723SRajesh Yadav } 1074b77d0f0dSSean Paul 1075b77d0f0dSSean Paul pm_runtime_put_sync(crtc->dev->dev); 107625fdd593SJeykumar Sankaran } 107725fdd593SJeykumar Sankaran 107825fdd593SJeykumar Sankaran static void dpu_crtc_enable(struct drm_crtc *crtc, 1079351f950dSMaxime Ripard struct drm_atomic_state *state) 108025fdd593SJeykumar Sankaran { 1081e12e5263SRob Clark struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 108225fdd593SJeykumar Sankaran struct drm_encoder *encoder; 108335c719daSRob Clark bool request_bandwidth = false; 108425fdd593SJeykumar Sankaran 1085b77d0f0dSSean Paul pm_runtime_get_sync(crtc->dev->dev); 1086b77d0f0dSSean Paul 108725fdd593SJeykumar Sankaran DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); 108825fdd593SJeykumar Sankaran 1089241b507cSRob Clark drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { 1090241b507cSRob Clark /* in video mode, we hold an extra bandwidth reference 1091241b507cSRob Clark * as we cannot drop bandwidth at frame-done if any 1092241b507cSRob Clark * crtc is being used in video mode. 1093241b507cSRob Clark */ 1094241b507cSRob Clark if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) 1095241b507cSRob Clark request_bandwidth = true; 109625fdd593SJeykumar Sankaran dpu_encoder_register_frame_event_callback(encoder, 109725fdd593SJeykumar Sankaran dpu_crtc_frame_event_cb, (void *)crtc); 1098241b507cSRob Clark } 1099241b507cSRob Clark 1100241b507cSRob Clark if (request_bandwidth) 1101241b507cSRob Clark atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); 110225fdd593SJeykumar Sankaran 110325fdd593SJeykumar Sankaran trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); 110425fdd593SJeykumar Sankaran dpu_crtc->enabled = true; 110525fdd593SJeykumar Sankaran 1106a796ba2cSSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 1107a796ba2cSSean Paul dpu_encoder_assign_crtc(encoder, crtc); 110825fdd593SJeykumar Sankaran 11092f2eb723SRajesh Yadav /* Enable/restore vblank irq handling */ 11102f2eb723SRajesh Yadav drm_crtc_vblank_on(crtc); 111125fdd593SJeykumar Sankaran } 111225fdd593SJeykumar Sankaran 111325fdd593SJeykumar Sankaran struct plane_state { 111425fdd593SJeykumar Sankaran struct dpu_plane_state *dpu_pstate; 111525fdd593SJeykumar Sankaran const struct drm_plane_state *drm_pstate; 111625fdd593SJeykumar Sankaran int stage; 111725fdd593SJeykumar Sankaran u32 pipe_id; 111825fdd593SJeykumar Sankaran }; 111925fdd593SJeykumar Sankaran 11209e4dde28SRob Clark static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate) 11219e4dde28SRob Clark { 11229e4dde28SRob Clark struct drm_crtc *crtc = cstate->crtc; 11239e4dde28SRob Clark struct drm_encoder *encoder; 11249e4dde28SRob Clark 11259e4dde28SRob Clark drm_for_each_encoder_mask (encoder, crtc->dev, cstate->encoder_mask) { 11269e4dde28SRob Clark if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) { 11279e4dde28SRob Clark return true; 11289e4dde28SRob Clark } 11299e4dde28SRob Clark } 11309e4dde28SRob Clark 11319e4dde28SRob Clark return false; 11329e4dde28SRob Clark } 11339e4dde28SRob Clark 113425fdd593SJeykumar Sankaran static int dpu_crtc_atomic_check(struct drm_crtc *crtc, 113529b77ad7SMaxime Ripard struct drm_atomic_state *state) 113625fdd593SJeykumar Sankaran { 113729b77ad7SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, 113829b77ad7SMaxime Ripard crtc); 1139e12e5263SRob Clark struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 114029b77ad7SMaxime Ripard struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc_state); 114125fdd593SJeykumar Sankaran struct plane_state *pstates; 114225fdd593SJeykumar Sankaran 114325fdd593SJeykumar Sankaran const struct drm_plane_state *pstate; 114425fdd593SJeykumar Sankaran struct drm_plane *plane; 114525fdd593SJeykumar Sankaran struct drm_display_mode *mode; 114625fdd593SJeykumar Sankaran 114722f76094SStephen Boyd int cnt = 0, rc = 0, mixer_width = 0, i, z_pos; 114825fdd593SJeykumar Sankaran 114925fdd593SJeykumar Sankaran struct dpu_multirect_plane_states multirect_plane[DPU_STAGE_MAX * 2]; 115025fdd593SJeykumar Sankaran int multirect_count = 0; 115125fdd593SJeykumar Sankaran const struct drm_plane_state *pipe_staged[SSPP_MAX]; 115225fdd593SJeykumar Sankaran int left_zpos_cnt = 0, right_zpos_cnt = 0; 115325fdd593SJeykumar Sankaran struct drm_rect crtc_rect = { 0 }; 11549e4dde28SRob Clark bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state); 115525fdd593SJeykumar Sankaran 115625fdd593SJeykumar Sankaran pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL); 115725fdd593SJeykumar Sankaran 115829b77ad7SMaxime Ripard if (!crtc_state->enable || !crtc_state->active) { 11595b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n", 116029b77ad7SMaxime Ripard crtc->base.id, crtc_state->enable, 116129b77ad7SMaxime Ripard crtc_state->active); 1162a29c8c02SKalyan Thota memset(&cstate->new_perf, 0, sizeof(cstate->new_perf)); 116325fdd593SJeykumar Sankaran goto end; 116425fdd593SJeykumar Sankaran } 116525fdd593SJeykumar Sankaran 116629b77ad7SMaxime Ripard mode = &crtc_state->adjusted_mode; 11675b702d78SStephen Boyd DRM_DEBUG_ATOMIC("%s: check\n", dpu_crtc->name); 116825fdd593SJeykumar Sankaran 116925fdd593SJeykumar Sankaran /* force a full mode set if active state changed */ 117029b77ad7SMaxime Ripard if (crtc_state->active_changed) 117129b77ad7SMaxime Ripard crtc_state->mode_changed = true; 117225fdd593SJeykumar Sankaran 117325fdd593SJeykumar Sankaran memset(pipe_staged, 0, sizeof(pipe_staged)); 117425fdd593SJeykumar Sankaran 117522f76094SStephen Boyd if (cstate->num_mixers) { 11763804a982SJordan Crouse mixer_width = mode->hdisplay / cstate->num_mixers; 117725fdd593SJeykumar Sankaran 117829b77ad7SMaxime Ripard _dpu_crtc_setup_lm_bounds(crtc, crtc_state); 117922f76094SStephen Boyd } 118025fdd593SJeykumar Sankaran 118125fdd593SJeykumar Sankaran crtc_rect.x2 = mode->hdisplay; 118225fdd593SJeykumar Sankaran crtc_rect.y2 = mode->vdisplay; 118325fdd593SJeykumar Sankaran 118425fdd593SJeykumar Sankaran /* get plane state for all drm planes associated with crtc state */ 118529b77ad7SMaxime Ripard drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) { 11869e4dde28SRob Clark struct dpu_plane_state *dpu_pstate = to_dpu_plane_state(pstate); 118725fdd593SJeykumar Sankaran struct drm_rect dst, clip = crtc_rect; 118825fdd593SJeykumar Sankaran 118925fdd593SJeykumar Sankaran if (IS_ERR_OR_NULL(pstate)) { 119025fdd593SJeykumar Sankaran rc = PTR_ERR(pstate); 119125fdd593SJeykumar Sankaran DPU_ERROR("%s: failed to get plane%d state, %d\n", 119225fdd593SJeykumar Sankaran dpu_crtc->name, plane->base.id, rc); 119325fdd593SJeykumar Sankaran goto end; 119425fdd593SJeykumar Sankaran } 119525fdd593SJeykumar Sankaran if (cnt >= DPU_STAGE_MAX * 4) 119625fdd593SJeykumar Sankaran continue; 119725fdd593SJeykumar Sankaran 11989e4dde28SRob Clark pstates[cnt].dpu_pstate = dpu_pstate; 119925fdd593SJeykumar Sankaran pstates[cnt].drm_pstate = pstate; 120025fdd593SJeykumar Sankaran pstates[cnt].stage = pstate->normalized_zpos; 120125fdd593SJeykumar Sankaran pstates[cnt].pipe_id = dpu_plane_pipe(plane); 120225fdd593SJeykumar Sankaran 12039e4dde28SRob Clark dpu_pstate->needs_dirtyfb = needs_dirtyfb; 12049e4dde28SRob Clark 120525fdd593SJeykumar Sankaran if (pipe_staged[pstates[cnt].pipe_id]) { 120625fdd593SJeykumar Sankaran multirect_plane[multirect_count].r0 = 120725fdd593SJeykumar Sankaran pipe_staged[pstates[cnt].pipe_id]; 120825fdd593SJeykumar Sankaran multirect_plane[multirect_count].r1 = pstate; 120925fdd593SJeykumar Sankaran multirect_count++; 121025fdd593SJeykumar Sankaran 121125fdd593SJeykumar Sankaran pipe_staged[pstates[cnt].pipe_id] = NULL; 121225fdd593SJeykumar Sankaran } else { 121325fdd593SJeykumar Sankaran pipe_staged[pstates[cnt].pipe_id] = pstate; 121425fdd593SJeykumar Sankaran } 121525fdd593SJeykumar Sankaran 121625fdd593SJeykumar Sankaran cnt++; 121725fdd593SJeykumar Sankaran 121825fdd593SJeykumar Sankaran dst = drm_plane_state_dest(pstate); 121996fc56a7SSean Paul if (!drm_rect_intersect(&clip, &dst)) { 122025fdd593SJeykumar Sankaran DPU_ERROR("invalid vertical/horizontal destination\n"); 122125fdd593SJeykumar Sankaran DPU_ERROR("display: " DRM_RECT_FMT " plane: " 122225fdd593SJeykumar Sankaran DRM_RECT_FMT "\n", DRM_RECT_ARG(&crtc_rect), 122325fdd593SJeykumar Sankaran DRM_RECT_ARG(&dst)); 122425fdd593SJeykumar Sankaran rc = -E2BIG; 122525fdd593SJeykumar Sankaran goto end; 122625fdd593SJeykumar Sankaran } 122725fdd593SJeykumar Sankaran } 122825fdd593SJeykumar Sankaran 122925fdd593SJeykumar Sankaran for (i = 1; i < SSPP_MAX; i++) { 123025fdd593SJeykumar Sankaran if (pipe_staged[i]) { 123125fdd593SJeykumar Sankaran dpu_plane_clear_multirect(pipe_staged[i]); 123225fdd593SJeykumar Sankaran 123325fdd593SJeykumar Sankaran if (is_dpu_plane_virtual(pipe_staged[i]->plane)) { 123425fdd593SJeykumar Sankaran DPU_ERROR( 123525fdd593SJeykumar Sankaran "r1 only virt plane:%d not supported\n", 123625fdd593SJeykumar Sankaran pipe_staged[i]->plane->base.id); 123725fdd593SJeykumar Sankaran rc = -EINVAL; 123825fdd593SJeykumar Sankaran goto end; 123925fdd593SJeykumar Sankaran } 124025fdd593SJeykumar Sankaran } 124125fdd593SJeykumar Sankaran } 124225fdd593SJeykumar Sankaran 124325fdd593SJeykumar Sankaran z_pos = -1; 124425fdd593SJeykumar Sankaran for (i = 0; i < cnt; i++) { 124525fdd593SJeykumar Sankaran /* reset counts at every new blend stage */ 124625fdd593SJeykumar Sankaran if (pstates[i].stage != z_pos) { 124725fdd593SJeykumar Sankaran left_zpos_cnt = 0; 124825fdd593SJeykumar Sankaran right_zpos_cnt = 0; 124925fdd593SJeykumar Sankaran z_pos = pstates[i].stage; 125025fdd593SJeykumar Sankaran } 125125fdd593SJeykumar Sankaran 125225fdd593SJeykumar Sankaran /* verify z_pos setting before using it */ 125325fdd593SJeykumar Sankaran if (z_pos >= DPU_STAGE_MAX - DPU_STAGE_0) { 125425fdd593SJeykumar Sankaran DPU_ERROR("> %d plane stages assigned\n", 125525fdd593SJeykumar Sankaran DPU_STAGE_MAX - DPU_STAGE_0); 125625fdd593SJeykumar Sankaran rc = -EINVAL; 125725fdd593SJeykumar Sankaran goto end; 125825fdd593SJeykumar Sankaran } else if (pstates[i].drm_pstate->crtc_x < mixer_width) { 125925fdd593SJeykumar Sankaran if (left_zpos_cnt == 2) { 126025fdd593SJeykumar Sankaran DPU_ERROR("> 2 planes @ stage %d on left\n", 126125fdd593SJeykumar Sankaran z_pos); 126225fdd593SJeykumar Sankaran rc = -EINVAL; 126325fdd593SJeykumar Sankaran goto end; 126425fdd593SJeykumar Sankaran } 126525fdd593SJeykumar Sankaran left_zpos_cnt++; 126625fdd593SJeykumar Sankaran 126725fdd593SJeykumar Sankaran } else { 126825fdd593SJeykumar Sankaran if (right_zpos_cnt == 2) { 126925fdd593SJeykumar Sankaran DPU_ERROR("> 2 planes @ stage %d on right\n", 127025fdd593SJeykumar Sankaran z_pos); 127125fdd593SJeykumar Sankaran rc = -EINVAL; 127225fdd593SJeykumar Sankaran goto end; 127325fdd593SJeykumar Sankaran } 127425fdd593SJeykumar Sankaran right_zpos_cnt++; 127525fdd593SJeykumar Sankaran } 127625fdd593SJeykumar Sankaran 127725fdd593SJeykumar Sankaran pstates[i].dpu_pstate->stage = z_pos + DPU_STAGE_0; 12785b702d78SStephen Boyd DRM_DEBUG_ATOMIC("%s: zpos %d\n", dpu_crtc->name, z_pos); 127925fdd593SJeykumar Sankaran } 128025fdd593SJeykumar Sankaran 128125fdd593SJeykumar Sankaran for (i = 0; i < multirect_count; i++) { 128225fdd593SJeykumar Sankaran if (dpu_plane_validate_multirect_v2(&multirect_plane[i])) { 128325fdd593SJeykumar Sankaran DPU_ERROR( 128425fdd593SJeykumar Sankaran "multirect validation failed for planes (%d - %d)\n", 128525fdd593SJeykumar Sankaran multirect_plane[i].r0->plane->base.id, 128625fdd593SJeykumar Sankaran multirect_plane[i].r1->plane->base.id); 128725fdd593SJeykumar Sankaran rc = -EINVAL; 128825fdd593SJeykumar Sankaran goto end; 128925fdd593SJeykumar Sankaran } 129025fdd593SJeykumar Sankaran } 129125fdd593SJeykumar Sankaran 1292241b507cSRob Clark atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); 1293241b507cSRob Clark 129429b77ad7SMaxime Ripard rc = dpu_core_perf_crtc_check(crtc, crtc_state); 129525fdd593SJeykumar Sankaran if (rc) { 129625fdd593SJeykumar Sankaran DPU_ERROR("crtc%d failed performance check %d\n", 129725fdd593SJeykumar Sankaran crtc->base.id, rc); 129825fdd593SJeykumar Sankaran goto end; 129925fdd593SJeykumar Sankaran } 130025fdd593SJeykumar Sankaran 130125fdd593SJeykumar Sankaran /* validate source split: 130225fdd593SJeykumar Sankaran * use pstates sorted by stage to check planes on same stage 130325fdd593SJeykumar Sankaran * we assume that all pipes are in source split so its valid to compare 130425fdd593SJeykumar Sankaran * without taking into account left/right mixer placement 130525fdd593SJeykumar Sankaran */ 130625fdd593SJeykumar Sankaran for (i = 1; i < cnt; i++) { 130725fdd593SJeykumar Sankaran struct plane_state *prv_pstate, *cur_pstate; 130825fdd593SJeykumar Sankaran struct drm_rect left_rect, right_rect; 130925fdd593SJeykumar Sankaran int32_t left_pid, right_pid; 131025fdd593SJeykumar Sankaran int32_t stage; 131125fdd593SJeykumar Sankaran 131225fdd593SJeykumar Sankaran prv_pstate = &pstates[i - 1]; 131325fdd593SJeykumar Sankaran cur_pstate = &pstates[i]; 131425fdd593SJeykumar Sankaran if (prv_pstate->stage != cur_pstate->stage) 131525fdd593SJeykumar Sankaran continue; 131625fdd593SJeykumar Sankaran 131725fdd593SJeykumar Sankaran stage = cur_pstate->stage; 131825fdd593SJeykumar Sankaran 131925fdd593SJeykumar Sankaran left_pid = prv_pstate->dpu_pstate->base.plane->base.id; 132025fdd593SJeykumar Sankaran left_rect = drm_plane_state_dest(prv_pstate->drm_pstate); 132125fdd593SJeykumar Sankaran 132225fdd593SJeykumar Sankaran right_pid = cur_pstate->dpu_pstate->base.plane->base.id; 132325fdd593SJeykumar Sankaran right_rect = drm_plane_state_dest(cur_pstate->drm_pstate); 132425fdd593SJeykumar Sankaran 132525fdd593SJeykumar Sankaran if (right_rect.x1 < left_rect.x1) { 132625fdd593SJeykumar Sankaran swap(left_pid, right_pid); 132725fdd593SJeykumar Sankaran swap(left_rect, right_rect); 132825fdd593SJeykumar Sankaran } 132925fdd593SJeykumar Sankaran 133025fdd593SJeykumar Sankaran /** 133125fdd593SJeykumar Sankaran * - planes are enumerated in pipe-priority order such that 133225fdd593SJeykumar Sankaran * planes with lower drm_id must be left-most in a shared 133325fdd593SJeykumar Sankaran * blend-stage when using source split. 133425fdd593SJeykumar Sankaran * - planes in source split must be contiguous in width 133525fdd593SJeykumar Sankaran * - planes in source split must have same dest yoff and height 133625fdd593SJeykumar Sankaran */ 133725fdd593SJeykumar Sankaran if (right_pid < left_pid) { 133825fdd593SJeykumar Sankaran DPU_ERROR( 133925fdd593SJeykumar Sankaran "invalid src split cfg. priority mismatch. stage: %d left: %d right: %d\n", 134025fdd593SJeykumar Sankaran stage, left_pid, right_pid); 134125fdd593SJeykumar Sankaran rc = -EINVAL; 134225fdd593SJeykumar Sankaran goto end; 134325fdd593SJeykumar Sankaran } else if (right_rect.x1 != drm_rect_width(&left_rect)) { 134425fdd593SJeykumar Sankaran DPU_ERROR("non-contiguous coordinates for src split. " 134525fdd593SJeykumar Sankaran "stage: %d left: " DRM_RECT_FMT " right: " 134625fdd593SJeykumar Sankaran DRM_RECT_FMT "\n", stage, 134725fdd593SJeykumar Sankaran DRM_RECT_ARG(&left_rect), 134825fdd593SJeykumar Sankaran DRM_RECT_ARG(&right_rect)); 134925fdd593SJeykumar Sankaran rc = -EINVAL; 135025fdd593SJeykumar Sankaran goto end; 135125fdd593SJeykumar Sankaran } else if (left_rect.y1 != right_rect.y1 || 135225fdd593SJeykumar Sankaran drm_rect_height(&left_rect) != drm_rect_height(&right_rect)) { 135325fdd593SJeykumar Sankaran DPU_ERROR("source split at stage: %d. invalid " 135425fdd593SJeykumar Sankaran "yoff/height: left: " DRM_RECT_FMT " right: " 135525fdd593SJeykumar Sankaran DRM_RECT_FMT "\n", stage, 135625fdd593SJeykumar Sankaran DRM_RECT_ARG(&left_rect), 135725fdd593SJeykumar Sankaran DRM_RECT_ARG(&right_rect)); 135825fdd593SJeykumar Sankaran rc = -EINVAL; 135925fdd593SJeykumar Sankaran goto end; 136025fdd593SJeykumar Sankaran } 136125fdd593SJeykumar Sankaran } 136225fdd593SJeykumar Sankaran 136325fdd593SJeykumar Sankaran end: 136425fdd593SJeykumar Sankaran kfree(pstates); 136525fdd593SJeykumar Sankaran return rc; 136625fdd593SJeykumar Sankaran } 136725fdd593SJeykumar Sankaran 136825fdd593SJeykumar Sankaran int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) 136925fdd593SJeykumar Sankaran { 13707a007a12SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 1371a796ba2cSSean Paul struct drm_encoder *enc; 137225fdd593SJeykumar Sankaran 137325fdd593SJeykumar Sankaran trace_dpu_crtc_vblank(DRMID(&dpu_crtc->base), en, dpu_crtc); 1374a796ba2cSSean Paul 1375a796ba2cSSean Paul /* 1376a796ba2cSSean Paul * Normally we would iterate through encoder_mask in crtc state to find 1377a796ba2cSSean Paul * attached encoders. In this case, we might be disabling vblank _after_ 1378a796ba2cSSean Paul * encoder_mask has been cleared. 1379a796ba2cSSean Paul * 1380a796ba2cSSean Paul * Instead, we "assign" a crtc to the encoder in enable and clear it in 1381a796ba2cSSean Paul * disable (which is also after encoder_mask is cleared). So instead of 1382a796ba2cSSean Paul * using encoder mask, we'll ask the encoder to toggle itself iff it's 1383a796ba2cSSean Paul * currently assigned to our crtc. 1384a796ba2cSSean Paul * 1385a796ba2cSSean Paul * Note also that this function cannot be called while crtc is disabled 1386a796ba2cSSean Paul * since we use drm_crtc_vblank_on/off. So we don't need to worry 1387a796ba2cSSean Paul * about the assigned crtcs being inconsistent with the current state 1388a796ba2cSSean Paul * (which means no need to worry about modeset locks). 1389a796ba2cSSean Paul */ 1390a796ba2cSSean Paul list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { 1391a796ba2cSSean Paul trace_dpu_crtc_vblank_enable(DRMID(crtc), DRMID(enc), en, 1392a796ba2cSSean Paul dpu_crtc); 1393a796ba2cSSean Paul 1394a796ba2cSSean Paul dpu_encoder_toggle_vblank_for_crtc(enc, crtc, en); 139525fdd593SJeykumar Sankaran } 139625fdd593SJeykumar Sankaran 139725fdd593SJeykumar Sankaran return 0; 139825fdd593SJeykumar Sankaran } 139925fdd593SJeykumar Sankaran 140025fdd593SJeykumar Sankaran #ifdef CONFIG_DEBUG_FS 140125fdd593SJeykumar Sankaran static int _dpu_debugfs_status_show(struct seq_file *s, void *data) 140225fdd593SJeykumar Sankaran { 140325fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc; 140425fdd593SJeykumar Sankaran struct dpu_plane_state *pstate = NULL; 140525fdd593SJeykumar Sankaran struct dpu_crtc_mixer *m; 140625fdd593SJeykumar Sankaran 140725fdd593SJeykumar Sankaran struct drm_crtc *crtc; 140825fdd593SJeykumar Sankaran struct drm_plane *plane; 140925fdd593SJeykumar Sankaran struct drm_display_mode *mode; 141025fdd593SJeykumar Sankaran struct drm_framebuffer *fb; 141125fdd593SJeykumar Sankaran struct drm_plane_state *state; 141225fdd593SJeykumar Sankaran struct dpu_crtc_state *cstate; 141325fdd593SJeykumar Sankaran 141425fdd593SJeykumar Sankaran int i, out_width; 141525fdd593SJeykumar Sankaran 141625fdd593SJeykumar Sankaran dpu_crtc = s->private; 141725fdd593SJeykumar Sankaran crtc = &dpu_crtc->base; 14189222cdd2SJeykumar Sankaran 14199222cdd2SJeykumar Sankaran drm_modeset_lock_all(crtc->dev); 142025fdd593SJeykumar Sankaran cstate = to_dpu_crtc_state(crtc->state); 142125fdd593SJeykumar Sankaran 142225fdd593SJeykumar Sankaran mode = &crtc->state->adjusted_mode; 14233804a982SJordan Crouse out_width = mode->hdisplay / cstate->num_mixers; 142425fdd593SJeykumar Sankaran 142525fdd593SJeykumar Sankaran seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id, 142625fdd593SJeykumar Sankaran mode->hdisplay, mode->vdisplay); 142725fdd593SJeykumar Sankaran 142825fdd593SJeykumar Sankaran seq_puts(s, "\n"); 142925fdd593SJeykumar Sankaran 14309222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; ++i) { 14319222cdd2SJeykumar Sankaran m = &cstate->mixers[i]; 143225fdd593SJeykumar Sankaran seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", 1433cf6916f4SJeykumar Sankaran m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0, 143425fdd593SJeykumar Sankaran out_width, mode->vdisplay); 143525fdd593SJeykumar Sankaran } 143625fdd593SJeykumar Sankaran 143725fdd593SJeykumar Sankaran seq_puts(s, "\n"); 143825fdd593SJeykumar Sankaran 143925fdd593SJeykumar Sankaran drm_atomic_crtc_for_each_plane(plane, crtc) { 144025fdd593SJeykumar Sankaran pstate = to_dpu_plane_state(plane->state); 144125fdd593SJeykumar Sankaran state = plane->state; 144225fdd593SJeykumar Sankaran 144325fdd593SJeykumar Sankaran if (!pstate || !state) 144425fdd593SJeykumar Sankaran continue; 144525fdd593SJeykumar Sankaran 144625fdd593SJeykumar Sankaran seq_printf(s, "\tplane:%u stage:%d\n", plane->base.id, 144725fdd593SJeykumar Sankaran pstate->stage); 144825fdd593SJeykumar Sankaran 144925fdd593SJeykumar Sankaran if (plane->state->fb) { 145025fdd593SJeykumar Sankaran fb = plane->state->fb; 145125fdd593SJeykumar Sankaran 145225fdd593SJeykumar Sankaran seq_printf(s, "\tfb:%d image format:%4.4s wxh:%ux%u ", 145325fdd593SJeykumar Sankaran fb->base.id, (char *) &fb->format->format, 145425fdd593SJeykumar Sankaran fb->width, fb->height); 145525fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(fb->format->cpp); ++i) 145625fdd593SJeykumar Sankaran seq_printf(s, "cpp[%d]:%u ", 145725fdd593SJeykumar Sankaran i, fb->format->cpp[i]); 145825fdd593SJeykumar Sankaran seq_puts(s, "\n\t"); 145925fdd593SJeykumar Sankaran 146025fdd593SJeykumar Sankaran seq_printf(s, "modifier:%8llu ", fb->modifier); 146125fdd593SJeykumar Sankaran seq_puts(s, "\n"); 146225fdd593SJeykumar Sankaran 146325fdd593SJeykumar Sankaran seq_puts(s, "\t"); 146425fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) 146525fdd593SJeykumar Sankaran seq_printf(s, "pitches[%d]:%8u ", i, 146625fdd593SJeykumar Sankaran fb->pitches[i]); 146725fdd593SJeykumar Sankaran seq_puts(s, "\n"); 146825fdd593SJeykumar Sankaran 146925fdd593SJeykumar Sankaran seq_puts(s, "\t"); 147025fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) 147125fdd593SJeykumar Sankaran seq_printf(s, "offsets[%d]:%8u ", i, 147225fdd593SJeykumar Sankaran fb->offsets[i]); 147325fdd593SJeykumar Sankaran seq_puts(s, "\n"); 147425fdd593SJeykumar Sankaran } 147525fdd593SJeykumar Sankaran 147625fdd593SJeykumar Sankaran seq_printf(s, "\tsrc_x:%4d src_y:%4d src_w:%4d src_h:%4d\n", 147725fdd593SJeykumar Sankaran state->src_x, state->src_y, state->src_w, state->src_h); 147825fdd593SJeykumar Sankaran 147925fdd593SJeykumar Sankaran seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n", 148025fdd593SJeykumar Sankaran state->crtc_x, state->crtc_y, state->crtc_w, 148125fdd593SJeykumar Sankaran state->crtc_h); 148225fdd593SJeykumar Sankaran seq_printf(s, "\tmultirect: mode: %d index: %d\n", 148325fdd593SJeykumar Sankaran pstate->multirect_mode, pstate->multirect_index); 148425fdd593SJeykumar Sankaran 148525fdd593SJeykumar Sankaran seq_puts(s, "\n"); 148625fdd593SJeykumar Sankaran } 148725fdd593SJeykumar Sankaran if (dpu_crtc->vblank_cb_count) { 148825fdd593SJeykumar Sankaran ktime_t diff = ktime_sub(ktime_get(), dpu_crtc->vblank_cb_time); 148925fdd593SJeykumar Sankaran s64 diff_ms = ktime_to_ms(diff); 149025fdd593SJeykumar Sankaran s64 fps = diff_ms ? div_s64( 149125fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_count * 1000, diff_ms) : 0; 149225fdd593SJeykumar Sankaran 149325fdd593SJeykumar Sankaran seq_printf(s, 149425fdd593SJeykumar Sankaran "vblank fps:%lld count:%u total:%llums total_framecount:%llu\n", 149525fdd593SJeykumar Sankaran fps, dpu_crtc->vblank_cb_count, 149625fdd593SJeykumar Sankaran ktime_to_ms(diff), dpu_crtc->play_count); 149725fdd593SJeykumar Sankaran 149825fdd593SJeykumar Sankaran /* reset time & count for next measurement */ 149925fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_count = 0; 150025fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_time = ktime_set(0, 0); 150125fdd593SJeykumar Sankaran } 150225fdd593SJeykumar Sankaran 15039222cdd2SJeykumar Sankaran drm_modeset_unlock_all(crtc->dev); 150425fdd593SJeykumar Sankaran 150525fdd593SJeykumar Sankaran return 0; 150625fdd593SJeykumar Sankaran } 150725fdd593SJeykumar Sankaran 1508341a361cSQinglang Miao DEFINE_SHOW_ATTRIBUTE(_dpu_debugfs_status); 150925fdd593SJeykumar Sankaran 151025fdd593SJeykumar Sankaran static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v) 151125fdd593SJeykumar Sankaran { 151225fdd593SJeykumar Sankaran struct drm_crtc *crtc = (struct drm_crtc *) s->private; 151325fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 151425fdd593SJeykumar Sankaran 151525fdd593SJeykumar Sankaran seq_printf(s, "client type: %d\n", dpu_crtc_get_client_type(crtc)); 151625fdd593SJeykumar Sankaran seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc)); 151725fdd593SJeykumar Sankaran seq_printf(s, "core_clk_rate: %llu\n", 151825fdd593SJeykumar Sankaran dpu_crtc->cur_perf.core_clk_rate); 1519cb88482eSJayant Shekhar seq_printf(s, "bw_ctl: %llu\n", dpu_crtc->cur_perf.bw_ctl); 1520cb88482eSJayant Shekhar seq_printf(s, "max_per_pipe_ib: %llu\n", 1521cb88482eSJayant Shekhar dpu_crtc->cur_perf.max_per_pipe_ib); 152225fdd593SJeykumar Sankaran 152325fdd593SJeykumar Sankaran return 0; 152425fdd593SJeykumar Sankaran } 1525341a361cSQinglang Miao DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state); 152625fdd593SJeykumar Sankaran 152725fdd593SJeykumar Sankaran static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) 152825fdd593SJeykumar Sankaran { 15293d688410SJordan Crouse struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 1530927e8bcaSDmitry Baryshkov struct dentry *debugfs_root; 153125fdd593SJeykumar Sankaran 1532927e8bcaSDmitry Baryshkov debugfs_root = debugfs_create_dir(dpu_crtc->name, 153325fdd593SJeykumar Sankaran crtc->dev->primary->debugfs_root); 153425fdd593SJeykumar Sankaran 153525fdd593SJeykumar Sankaran debugfs_create_file("status", 0400, 1536927e8bcaSDmitry Baryshkov debugfs_root, 1537341a361cSQinglang Miao dpu_crtc, &_dpu_debugfs_status_fops); 153825fdd593SJeykumar Sankaran debugfs_create_file("state", 0600, 1539927e8bcaSDmitry Baryshkov debugfs_root, 154025fdd593SJeykumar Sankaran &dpu_crtc->base, 154125fdd593SJeykumar Sankaran &dpu_crtc_debugfs_state_fops); 154225fdd593SJeykumar Sankaran 154325fdd593SJeykumar Sankaran return 0; 154425fdd593SJeykumar Sankaran } 154525fdd593SJeykumar Sankaran #else 154625fdd593SJeykumar Sankaran static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) 154725fdd593SJeykumar Sankaran { 154825fdd593SJeykumar Sankaran return 0; 154925fdd593SJeykumar Sankaran } 155025fdd593SJeykumar Sankaran #endif /* CONFIG_DEBUG_FS */ 155125fdd593SJeykumar Sankaran 155225fdd593SJeykumar Sankaran static int dpu_crtc_late_register(struct drm_crtc *crtc) 155325fdd593SJeykumar Sankaran { 155425fdd593SJeykumar Sankaran return _dpu_crtc_init_debugfs(crtc); 155525fdd593SJeykumar Sankaran } 155625fdd593SJeykumar Sankaran 155725fdd593SJeykumar Sankaran static const struct drm_crtc_funcs dpu_crtc_funcs = { 155825fdd593SJeykumar Sankaran .set_config = drm_atomic_helper_set_config, 155925fdd593SJeykumar Sankaran .destroy = dpu_crtc_destroy, 156025fdd593SJeykumar Sankaran .page_flip = drm_atomic_helper_page_flip, 156125fdd593SJeykumar Sankaran .reset = dpu_crtc_reset, 156225fdd593SJeykumar Sankaran .atomic_duplicate_state = dpu_crtc_duplicate_state, 156325fdd593SJeykumar Sankaran .atomic_destroy_state = dpu_crtc_destroy_state, 156453b53337SDmitry Baryshkov .atomic_print_state = dpu_crtc_atomic_print_state, 156525fdd593SJeykumar Sankaran .late_register = dpu_crtc_late_register, 156678d9b458SJessica Zhang .verify_crc_source = dpu_crtc_verify_crc_source, 156778d9b458SJessica Zhang .set_crc_source = dpu_crtc_set_crc_source, 156876e8cfd8SThomas Zimmermann .enable_vblank = msm_crtc_enable_vblank, 156976e8cfd8SThomas Zimmermann .disable_vblank = msm_crtc_disable_vblank, 157073743e72SKalyan Thota .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, 157173743e72SKalyan Thota .get_vblank_counter = dpu_crtc_get_vblank_counter, 157225fdd593SJeykumar Sankaran }; 157325fdd593SJeykumar Sankaran 157425fdd593SJeykumar Sankaran static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { 1575f7aafc8dSSean Paul .atomic_disable = dpu_crtc_disable, 157625fdd593SJeykumar Sankaran .atomic_enable = dpu_crtc_enable, 157725fdd593SJeykumar Sankaran .atomic_check = dpu_crtc_atomic_check, 157825fdd593SJeykumar Sankaran .atomic_begin = dpu_crtc_atomic_begin, 157925fdd593SJeykumar Sankaran .atomic_flush = dpu_crtc_atomic_flush, 158073743e72SKalyan Thota .get_scanout_position = dpu_crtc_get_scanout_position, 158125fdd593SJeykumar Sankaran }; 158225fdd593SJeykumar Sankaran 158325fdd593SJeykumar Sankaran /* initialize crtc */ 158407ca1fc0SSravanthi Kollukuduru struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, 158507ca1fc0SSravanthi Kollukuduru struct drm_plane *cursor) 158625fdd593SJeykumar Sankaran { 158725fdd593SJeykumar Sankaran struct drm_crtc *crtc = NULL; 158825fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = NULL; 1589c17aeda0SJordan Crouse int i; 159025fdd593SJeykumar Sankaran 159125fdd593SJeykumar Sankaran dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); 159225fdd593SJeykumar Sankaran if (!dpu_crtc) 159325fdd593SJeykumar Sankaran return ERR_PTR(-ENOMEM); 159425fdd593SJeykumar Sankaran 159525fdd593SJeykumar Sankaran crtc = &dpu_crtc->base; 159625fdd593SJeykumar Sankaran crtc->dev = dev; 159725fdd593SJeykumar Sankaran 159825fdd593SJeykumar Sankaran spin_lock_init(&dpu_crtc->spin_lock); 159925fdd593SJeykumar Sankaran atomic_set(&dpu_crtc->frame_pending, 0); 160025fdd593SJeykumar Sankaran 160125fdd593SJeykumar Sankaran init_completion(&dpu_crtc->frame_done_comp); 160225fdd593SJeykumar Sankaran 160325fdd593SJeykumar Sankaran INIT_LIST_HEAD(&dpu_crtc->frame_event_list); 160425fdd593SJeykumar Sankaran 160525fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(dpu_crtc->frame_events); i++) { 160625fdd593SJeykumar Sankaran INIT_LIST_HEAD(&dpu_crtc->frame_events[i].list); 160725fdd593SJeykumar Sankaran list_add(&dpu_crtc->frame_events[i].list, 160825fdd593SJeykumar Sankaran &dpu_crtc->frame_event_list); 160925fdd593SJeykumar Sankaran kthread_init_work(&dpu_crtc->frame_events[i].work, 161025fdd593SJeykumar Sankaran dpu_crtc_frame_event_work); 161125fdd593SJeykumar Sankaran } 161225fdd593SJeykumar Sankaran 161307ca1fc0SSravanthi Kollukuduru drm_crtc_init_with_planes(dev, crtc, plane, cursor, &dpu_crtc_funcs, 161425fdd593SJeykumar Sankaran NULL); 161525fdd593SJeykumar Sankaran 161625fdd593SJeykumar Sankaran drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); 161725fdd593SJeykumar Sankaran 16184259ff7aSKalyan Thota drm_crtc_enable_color_mgmt(crtc, 0, true, 0); 16194259ff7aSKalyan Thota 162025fdd593SJeykumar Sankaran /* save user friendly CRTC name for later */ 162125fdd593SJeykumar Sankaran snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); 162225fdd593SJeykumar Sankaran 162325fdd593SJeykumar Sankaran /* initialize event handling */ 1624c17aeda0SJordan Crouse spin_lock_init(&dpu_crtc->event_lock); 162525fdd593SJeykumar Sankaran 16265b702d78SStephen Boyd DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name); 162725fdd593SJeykumar Sankaran return crtc; 162825fdd593SJeykumar Sankaran } 1629