1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 225fdd593SJeykumar Sankaran /* 378d9b458SJessica Zhang * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 425fdd593SJeykumar Sankaran * Copyright (C) 2013 Red Hat 525fdd593SJeykumar Sankaran * Author: Rob Clark <robdclark@gmail.com> 625fdd593SJeykumar Sankaran */ 725fdd593SJeykumar Sankaran 825fdd593SJeykumar Sankaran #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 925fdd593SJeykumar Sankaran #include <linux/sort.h> 1025fdd593SJeykumar Sankaran #include <linux/debugfs.h> 1125fdd593SJeykumar Sankaran #include <linux/ktime.h> 124259ff7aSKalyan Thota #include <linux/bits.h> 13feea39a8SSam Ravnborg 14351f950dSMaxime Ripard #include <drm/drm_atomic.h> 1525fdd593SJeykumar Sankaran #include <drm/drm_crtc.h> 1625fdd593SJeykumar Sankaran #include <drm/drm_flip_work.h> 17fcd70cd3SDaniel Vetter #include <drm/drm_mode.h> 18fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 1925fdd593SJeykumar Sankaran #include <drm/drm_rect.h> 20feea39a8SSam Ravnborg #include <drm/drm_vblank.h> 2125fdd593SJeykumar Sankaran 2225fdd593SJeykumar Sankaran #include "dpu_kms.h" 2325fdd593SJeykumar Sankaran #include "dpu_hw_lm.h" 2425fdd593SJeykumar Sankaran #include "dpu_hw_ctl.h" 254259ff7aSKalyan Thota #include "dpu_hw_dspp.h" 2625fdd593SJeykumar Sankaran #include "dpu_crtc.h" 2725fdd593SJeykumar Sankaran #include "dpu_plane.h" 2825fdd593SJeykumar Sankaran #include "dpu_encoder.h" 2925fdd593SJeykumar Sankaran #include "dpu_vbif.h" 3025fdd593SJeykumar Sankaran #include "dpu_core_perf.h" 3125fdd593SJeykumar Sankaran #include "dpu_trace.h" 3225fdd593SJeykumar Sankaran 3325fdd593SJeykumar Sankaran /* layer mixer index on dpu_crtc */ 3425fdd593SJeykumar Sankaran #define LEFT_MIXER 0 3525fdd593SJeykumar Sankaran #define RIGHT_MIXER 1 3625fdd593SJeykumar Sankaran 3770df9610SSean Paul /* timeout in ms waiting for frame done */ 3870df9610SSean Paul #define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 3970df9610SSean Paul 404259ff7aSKalyan Thota #define CONVERT_S3_15(val) \ 414259ff7aSKalyan Thota (((((u64)val) & ~BIT_ULL(63)) >> 17) & GENMASK_ULL(17, 0)) 424259ff7aSKalyan Thota 4358fba464SSean Paul static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) 4425fdd593SJeykumar Sankaran { 4504b96b63SBruce Wang struct msm_drm_private *priv = crtc->dev->dev_private; 4625fdd593SJeykumar Sankaran 4725fdd593SJeykumar Sankaran return to_dpu_kms(priv->kms); 4825fdd593SJeykumar Sankaran } 4925fdd593SJeykumar Sankaran 5025fdd593SJeykumar Sankaran static void dpu_crtc_destroy(struct drm_crtc *crtc) 5125fdd593SJeykumar Sankaran { 5225fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 5325fdd593SJeykumar Sankaran 5425fdd593SJeykumar Sankaran if (!crtc) 5525fdd593SJeykumar Sankaran return; 5625fdd593SJeykumar Sankaran 5725fdd593SJeykumar Sankaran drm_crtc_cleanup(crtc); 5825fdd593SJeykumar Sankaran kfree(dpu_crtc); 5925fdd593SJeykumar Sankaran } 6025fdd593SJeykumar Sankaran 6173743e72SKalyan Thota static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) 6273743e72SKalyan Thota { 6373743e72SKalyan Thota struct drm_device *dev = crtc->dev; 6473743e72SKalyan Thota struct drm_encoder *encoder; 6573743e72SKalyan Thota 6673743e72SKalyan Thota drm_for_each_encoder(encoder, dev) 6773743e72SKalyan Thota if (encoder->crtc == crtc) 6873743e72SKalyan Thota return encoder; 6973743e72SKalyan Thota 7073743e72SKalyan Thota return NULL; 7173743e72SKalyan Thota } 7273743e72SKalyan Thota 7378d9b458SJessica Zhang static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name) 7478d9b458SJessica Zhang { 7578d9b458SJessica Zhang if (!src_name || 7678d9b458SJessica Zhang !strcmp(src_name, "none")) 7778d9b458SJessica Zhang return DPU_CRTC_CRC_SOURCE_NONE; 7878d9b458SJessica Zhang if (!strcmp(src_name, "auto") || 7978d9b458SJessica Zhang !strcmp(src_name, "lm")) 8078d9b458SJessica Zhang return DPU_CRTC_CRC_SOURCE_LAYER_MIXER; 8178d9b458SJessica Zhang 8278d9b458SJessica Zhang return DPU_CRTC_CRC_SOURCE_INVALID; 8378d9b458SJessica Zhang } 8478d9b458SJessica Zhang 8578d9b458SJessica Zhang static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, 8678d9b458SJessica Zhang const char *src_name, size_t *values_cnt) 8778d9b458SJessica Zhang { 8878d9b458SJessica Zhang enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); 8978d9b458SJessica Zhang struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); 9078d9b458SJessica Zhang 9178d9b458SJessica Zhang if (source < 0) { 9278d9b458SJessica Zhang DRM_DEBUG_DRIVER("Invalid source %s for CRTC%d\n", src_name, crtc->index); 9378d9b458SJessica Zhang return -EINVAL; 9478d9b458SJessica Zhang } 9578d9b458SJessica Zhang 9678d9b458SJessica Zhang if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) 9778d9b458SJessica Zhang *values_cnt = crtc_state->num_mixers; 9878d9b458SJessica Zhang 9978d9b458SJessica Zhang return 0; 10078d9b458SJessica Zhang } 10178d9b458SJessica Zhang 10278d9b458SJessica Zhang static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) 10378d9b458SJessica Zhang { 10478d9b458SJessica Zhang enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); 10578d9b458SJessica Zhang enum dpu_crtc_crc_source current_source; 10678d9b458SJessica Zhang struct dpu_crtc_state *crtc_state; 10778d9b458SJessica Zhang struct drm_device *drm_dev = crtc->dev; 10878d9b458SJessica Zhang struct dpu_crtc_mixer *m; 10978d9b458SJessica Zhang 11078d9b458SJessica Zhang bool was_enabled; 11178d9b458SJessica Zhang bool enable = false; 11278d9b458SJessica Zhang int i, ret = 0; 11378d9b458SJessica Zhang 11478d9b458SJessica Zhang if (source < 0) { 11578d9b458SJessica Zhang DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index); 11678d9b458SJessica Zhang return -EINVAL; 11778d9b458SJessica Zhang } 11878d9b458SJessica Zhang 11978d9b458SJessica Zhang ret = drm_modeset_lock(&crtc->mutex, NULL); 12078d9b458SJessica Zhang 12178d9b458SJessica Zhang if (ret) 12278d9b458SJessica Zhang return ret; 12378d9b458SJessica Zhang 12478d9b458SJessica Zhang enable = (source != DPU_CRTC_CRC_SOURCE_NONE); 12578d9b458SJessica Zhang crtc_state = to_dpu_crtc_state(crtc->state); 12678d9b458SJessica Zhang 12778d9b458SJessica Zhang spin_lock_irq(&drm_dev->event_lock); 12878d9b458SJessica Zhang current_source = crtc_state->crc_source; 12978d9b458SJessica Zhang spin_unlock_irq(&drm_dev->event_lock); 13078d9b458SJessica Zhang 13178d9b458SJessica Zhang was_enabled = (current_source != DPU_CRTC_CRC_SOURCE_NONE); 13278d9b458SJessica Zhang 13378d9b458SJessica Zhang if (!was_enabled && enable) { 13478d9b458SJessica Zhang ret = drm_crtc_vblank_get(crtc); 13578d9b458SJessica Zhang 13678d9b458SJessica Zhang if (ret) 13778d9b458SJessica Zhang goto cleanup; 13878d9b458SJessica Zhang 13978d9b458SJessica Zhang } else if (was_enabled && !enable) { 14078d9b458SJessica Zhang drm_crtc_vblank_put(crtc); 14178d9b458SJessica Zhang } 14278d9b458SJessica Zhang 14378d9b458SJessica Zhang spin_lock_irq(&drm_dev->event_lock); 14478d9b458SJessica Zhang crtc_state->crc_source = source; 14578d9b458SJessica Zhang spin_unlock_irq(&drm_dev->event_lock); 14678d9b458SJessica Zhang 14778d9b458SJessica Zhang crtc_state->crc_frame_skip_count = 0; 14878d9b458SJessica Zhang 14978d9b458SJessica Zhang for (i = 0; i < crtc_state->num_mixers; ++i) { 15078d9b458SJessica Zhang m = &crtc_state->mixers[i]; 15178d9b458SJessica Zhang 15278d9b458SJessica Zhang if (!m->hw_lm || !m->hw_lm->ops.setup_misr) 15378d9b458SJessica Zhang continue; 15478d9b458SJessica Zhang 15578d9b458SJessica Zhang /* Calculate MISR over 1 frame */ 15678d9b458SJessica Zhang m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); 15778d9b458SJessica Zhang } 15878d9b458SJessica Zhang 15978d9b458SJessica Zhang 16078d9b458SJessica Zhang cleanup: 16178d9b458SJessica Zhang drm_modeset_unlock(&crtc->mutex); 16278d9b458SJessica Zhang 16378d9b458SJessica Zhang return ret; 16478d9b458SJessica Zhang } 16578d9b458SJessica Zhang 16673743e72SKalyan Thota static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) 16773743e72SKalyan Thota { 168885455d6SMark Yacoub struct drm_encoder *encoder = get_encoder_from_crtc(crtc); 16973743e72SKalyan Thota if (!encoder) { 17073743e72SKalyan Thota DRM_ERROR("no encoder found for crtc %d\n", crtc->index); 171885455d6SMark Yacoub return 0; 17273743e72SKalyan Thota } 17373743e72SKalyan Thota 174885455d6SMark Yacoub return dpu_encoder_get_vsync_count(encoder); 17573743e72SKalyan Thota } 17673743e72SKalyan Thota 17778d9b458SJessica Zhang 17878d9b458SJessica Zhang static int dpu_crtc_get_crc(struct drm_crtc *crtc) 17978d9b458SJessica Zhang { 18078d9b458SJessica Zhang struct dpu_crtc_state *crtc_state; 18178d9b458SJessica Zhang struct dpu_crtc_mixer *m; 18200326bfaSRob Clark u32 crcs[CRTC_DUAL_MIXERS]; 18378d9b458SJessica Zhang 18478d9b458SJessica Zhang int i = 0; 18578d9b458SJessica Zhang int rc = 0; 18678d9b458SJessica Zhang 18778d9b458SJessica Zhang crtc_state = to_dpu_crtc_state(crtc->state); 18878d9b458SJessica Zhang 18900326bfaSRob Clark BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers)); 19078d9b458SJessica Zhang 19178d9b458SJessica Zhang /* Skip first 2 frames in case of "uncooked" CRCs */ 19278d9b458SJessica Zhang if (crtc_state->crc_frame_skip_count < 2) { 19378d9b458SJessica Zhang crtc_state->crc_frame_skip_count++; 19400326bfaSRob Clark return 0; 19578d9b458SJessica Zhang } 19678d9b458SJessica Zhang 19778d9b458SJessica Zhang for (i = 0; i < crtc_state->num_mixers; ++i) { 19878d9b458SJessica Zhang 19978d9b458SJessica Zhang m = &crtc_state->mixers[i]; 20078d9b458SJessica Zhang 20178d9b458SJessica Zhang if (!m->hw_lm || !m->hw_lm->ops.collect_misr) 20278d9b458SJessica Zhang continue; 20378d9b458SJessica Zhang 20478d9b458SJessica Zhang rc = m->hw_lm->ops.collect_misr(m->hw_lm, &crcs[i]); 20578d9b458SJessica Zhang 20678d9b458SJessica Zhang if (rc) { 20778d9b458SJessica Zhang DRM_DEBUG_DRIVER("MISR read failed\n"); 20878d9b458SJessica Zhang return rc; 20978d9b458SJessica Zhang } 21000326bfaSRob Clark } 21100326bfaSRob Clark 21200326bfaSRob Clark return drm_crtc_add_crc_entry(crtc, true, 21300326bfaSRob Clark drm_crtc_accurate_vblank_count(crtc), crcs); 21400326bfaSRob Clark } 21578d9b458SJessica Zhang 21673743e72SKalyan Thota static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, 21773743e72SKalyan Thota bool in_vblank_irq, 21873743e72SKalyan Thota int *vpos, int *hpos, 21973743e72SKalyan Thota ktime_t *stime, ktime_t *etime, 22073743e72SKalyan Thota const struct drm_display_mode *mode) 22173743e72SKalyan Thota { 22273743e72SKalyan Thota unsigned int pipe = crtc->index; 22373743e72SKalyan Thota struct drm_encoder *encoder; 22473743e72SKalyan Thota int line, vsw, vbp, vactive_start, vactive_end, vfp_end; 22573743e72SKalyan Thota 22673743e72SKalyan Thota encoder = get_encoder_from_crtc(crtc); 22773743e72SKalyan Thota if (!encoder) { 22873743e72SKalyan Thota DRM_ERROR("no encoder found for crtc %d\n", pipe); 22973743e72SKalyan Thota return false; 23073743e72SKalyan Thota } 23173743e72SKalyan Thota 23273743e72SKalyan Thota vsw = mode->crtc_vsync_end - mode->crtc_vsync_start; 23373743e72SKalyan Thota vbp = mode->crtc_vtotal - mode->crtc_vsync_end; 23473743e72SKalyan Thota 23573743e72SKalyan Thota /* 23673743e72SKalyan Thota * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at 23773743e72SKalyan Thota * the end of VFP. Translate the porch values relative to the line 23873743e72SKalyan Thota * counter positions. 23973743e72SKalyan Thota */ 24073743e72SKalyan Thota 24173743e72SKalyan Thota vactive_start = vsw + vbp + 1; 24273743e72SKalyan Thota vactive_end = vactive_start + mode->crtc_vdisplay; 24373743e72SKalyan Thota 24473743e72SKalyan Thota /* last scan line before VSYNC */ 24573743e72SKalyan Thota vfp_end = mode->crtc_vtotal; 24673743e72SKalyan Thota 24773743e72SKalyan Thota if (stime) 24873743e72SKalyan Thota *stime = ktime_get(); 24973743e72SKalyan Thota 25073743e72SKalyan Thota line = dpu_encoder_get_linecount(encoder); 25173743e72SKalyan Thota 25273743e72SKalyan Thota if (line < vactive_start) 25373743e72SKalyan Thota line -= vactive_start; 25473743e72SKalyan Thota else if (line > vactive_end) 25573743e72SKalyan Thota line = line - vfp_end - vactive_start; 25673743e72SKalyan Thota else 25773743e72SKalyan Thota line -= vactive_start; 25873743e72SKalyan Thota 25973743e72SKalyan Thota *vpos = line; 26073743e72SKalyan Thota *hpos = 0; 26173743e72SKalyan Thota 26273743e72SKalyan Thota if (etime) 26373743e72SKalyan Thota *etime = ktime_get(); 26473743e72SKalyan Thota 26573743e72SKalyan Thota return true; 26673743e72SKalyan Thota } 26773743e72SKalyan Thota 26825fdd593SJeykumar Sankaran static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, 26974593a28SSravanthi Kollukuduru struct dpu_plane_state *pstate, struct dpu_format *format) 27025fdd593SJeykumar Sankaran { 27125fdd593SJeykumar Sankaran struct dpu_hw_mixer *lm = mixer->hw_lm; 27274593a28SSravanthi Kollukuduru uint32_t blend_op; 273f964cfb7SDmitry Baryshkov uint32_t fg_alpha, bg_alpha; 274f964cfb7SDmitry Baryshkov 275f964cfb7SDmitry Baryshkov fg_alpha = pstate->base.alpha >> 8; 276f964cfb7SDmitry Baryshkov bg_alpha = 0xff - fg_alpha; 27725fdd593SJeykumar Sankaran 27825fdd593SJeykumar Sankaran /* default to opaque blending */ 279f964cfb7SDmitry Baryshkov if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE || 280f964cfb7SDmitry Baryshkov !format->alpha_enable) { 28174593a28SSravanthi Kollukuduru blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | 28274593a28SSravanthi Kollukuduru DPU_BLEND_BG_ALPHA_BG_CONST; 283f964cfb7SDmitry Baryshkov } else if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) { 284f964cfb7SDmitry Baryshkov blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | 285f964cfb7SDmitry Baryshkov DPU_BLEND_BG_ALPHA_FG_PIXEL; 286f964cfb7SDmitry Baryshkov if (fg_alpha != 0xff) { 287f964cfb7SDmitry Baryshkov bg_alpha = fg_alpha; 288f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_BG_MOD_ALPHA | 289f964cfb7SDmitry Baryshkov DPU_BLEND_BG_INV_MOD_ALPHA; 290f964cfb7SDmitry Baryshkov } else { 291f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_BG_INV_ALPHA; 292f964cfb7SDmitry Baryshkov } 293f964cfb7SDmitry Baryshkov } else { 29474593a28SSravanthi Kollukuduru /* coverage blending */ 29574593a28SSravanthi Kollukuduru blend_op = DPU_BLEND_FG_ALPHA_FG_PIXEL | 296f964cfb7SDmitry Baryshkov DPU_BLEND_BG_ALPHA_FG_PIXEL; 297f964cfb7SDmitry Baryshkov if (fg_alpha != 0xff) { 298f964cfb7SDmitry Baryshkov bg_alpha = fg_alpha; 299f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_FG_MOD_ALPHA | 300f964cfb7SDmitry Baryshkov DPU_BLEND_FG_INV_MOD_ALPHA | 301f964cfb7SDmitry Baryshkov DPU_BLEND_BG_MOD_ALPHA | 302f964cfb7SDmitry Baryshkov DPU_BLEND_BG_INV_MOD_ALPHA; 303f964cfb7SDmitry Baryshkov } else { 304f964cfb7SDmitry Baryshkov blend_op |= DPU_BLEND_BG_INV_ALPHA; 305f964cfb7SDmitry Baryshkov } 30674593a28SSravanthi Kollukuduru } 30774593a28SSravanthi Kollukuduru 30874593a28SSravanthi Kollukuduru lm->ops.setup_blend_config(lm, pstate->stage, 309f964cfb7SDmitry Baryshkov fg_alpha, bg_alpha, blend_op); 31074593a28SSravanthi Kollukuduru 3115b702d78SStephen Boyd DRM_DEBUG_ATOMIC("format:%p4cc, alpha_en:%u blend_op:0x%x\n", 31292f1d09cSSakari Ailus &format->base.pixel_format, format->alpha_enable, blend_op); 31325fdd593SJeykumar Sankaran } 31425fdd593SJeykumar Sankaran 31525fdd593SJeykumar Sankaran static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) 31625fdd593SJeykumar Sankaran { 31725fdd593SJeykumar Sankaran struct dpu_crtc_state *crtc_state; 31825fdd593SJeykumar Sankaran int lm_idx, lm_horiz_position; 31925fdd593SJeykumar Sankaran 32025fdd593SJeykumar Sankaran crtc_state = to_dpu_crtc_state(crtc->state); 32125fdd593SJeykumar Sankaran 32225fdd593SJeykumar Sankaran lm_horiz_position = 0; 3239222cdd2SJeykumar Sankaran for (lm_idx = 0; lm_idx < crtc_state->num_mixers; lm_idx++) { 32425fdd593SJeykumar Sankaran const struct drm_rect *lm_roi = &crtc_state->lm_bounds[lm_idx]; 3259222cdd2SJeykumar Sankaran struct dpu_hw_mixer *hw_lm = crtc_state->mixers[lm_idx].hw_lm; 32625fdd593SJeykumar Sankaran struct dpu_hw_mixer_cfg cfg; 32725fdd593SJeykumar Sankaran 32825fdd593SJeykumar Sankaran if (!lm_roi || !drm_rect_visible(lm_roi)) 32925fdd593SJeykumar Sankaran continue; 33025fdd593SJeykumar Sankaran 33125fdd593SJeykumar Sankaran cfg.out_width = drm_rect_width(lm_roi); 33225fdd593SJeykumar Sankaran cfg.out_height = drm_rect_height(lm_roi); 33325fdd593SJeykumar Sankaran cfg.right_mixer = lm_horiz_position++; 33425fdd593SJeykumar Sankaran cfg.flags = 0; 33525fdd593SJeykumar Sankaran hw_lm->ops.setup_mixer_out(hw_lm, &cfg); 33625fdd593SJeykumar Sankaran } 33725fdd593SJeykumar Sankaran } 33825fdd593SJeykumar Sankaran 33925fdd593SJeykumar Sankaran static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, 34053c064a1SDmitry Baryshkov struct dpu_crtc *dpu_crtc, struct dpu_crtc_mixer *mixer, 34153c064a1SDmitry Baryshkov struct dpu_hw_stage_cfg *stage_cfg) 34225fdd593SJeykumar Sankaran { 34325fdd593SJeykumar Sankaran struct drm_plane *plane; 34425fdd593SJeykumar Sankaran struct drm_framebuffer *fb; 34525fdd593SJeykumar Sankaran struct drm_plane_state *state; 34604b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 34725fdd593SJeykumar Sankaran struct dpu_plane_state *pstate = NULL; 34825fdd593SJeykumar Sankaran struct dpu_format *format; 34904b96b63SBruce Wang struct dpu_hw_ctl *ctl = mixer->lm_ctl; 35025fdd593SJeykumar Sankaran 35125fdd593SJeykumar Sankaran u32 flush_mask; 35225fdd593SJeykumar Sankaran uint32_t stage_idx, lm_idx; 35325fdd593SJeykumar Sankaran int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 }; 35425fdd593SJeykumar Sankaran bool bg_alpha_enable = false; 355b3652e87SKrishna Manikandan DECLARE_BITMAP(fetch_active, SSPP_MAX); 35625fdd593SJeykumar Sankaran 357b3652e87SKrishna Manikandan memset(fetch_active, 0, sizeof(fetch_active)); 35825fdd593SJeykumar Sankaran drm_atomic_crtc_for_each_plane(plane, crtc) { 35925fdd593SJeykumar Sankaran state = plane->state; 36025fdd593SJeykumar Sankaran if (!state) 36125fdd593SJeykumar Sankaran continue; 36225fdd593SJeykumar Sankaran 36325fdd593SJeykumar Sankaran pstate = to_dpu_plane_state(state); 36425fdd593SJeykumar Sankaran fb = state->fb; 36525fdd593SJeykumar Sankaran 36625fdd593SJeykumar Sankaran dpu_plane_get_ctl_flush(plane, ctl, &flush_mask); 367b3652e87SKrishna Manikandan set_bit(dpu_plane_pipe(plane), fetch_active); 3685b702d78SStephen Boyd 3695b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc %d stage:%d - plane %d sspp %d fb %d\n", 37025fdd593SJeykumar Sankaran crtc->base.id, 37125fdd593SJeykumar Sankaran pstate->stage, 37225fdd593SJeykumar Sankaran plane->base.id, 37325fdd593SJeykumar Sankaran dpu_plane_pipe(plane) - SSPP_VIG0, 37425fdd593SJeykumar Sankaran state->fb ? state->fb->base.id : -1); 37525fdd593SJeykumar Sankaran 37625fdd593SJeykumar Sankaran format = to_dpu_format(msm_framebuffer_format(pstate->base.fb)); 37725fdd593SJeykumar Sankaran 37825fdd593SJeykumar Sankaran if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable) 37925fdd593SJeykumar Sankaran bg_alpha_enable = true; 38025fdd593SJeykumar Sankaran 38125fdd593SJeykumar Sankaran stage_idx = zpos_cnt[pstate->stage]++; 38225fdd593SJeykumar Sankaran stage_cfg->stage[pstate->stage][stage_idx] = 38325fdd593SJeykumar Sankaran dpu_plane_pipe(plane); 38425fdd593SJeykumar Sankaran stage_cfg->multirect_index[pstate->stage][stage_idx] = 38525fdd593SJeykumar Sankaran pstate->multirect_index; 38625fdd593SJeykumar Sankaran 38725fdd593SJeykumar Sankaran trace_dpu_crtc_setup_mixer(DRMID(crtc), DRMID(plane), 38825fdd593SJeykumar Sankaran state, pstate, stage_idx, 38925fdd593SJeykumar Sankaran dpu_plane_pipe(plane) - SSPP_VIG0, 39025fdd593SJeykumar Sankaran format->base.pixel_format, 39125fdd593SJeykumar Sankaran fb ? fb->modifier : 0); 39225fdd593SJeykumar Sankaran 39325fdd593SJeykumar Sankaran /* blend config update */ 3949222cdd2SJeykumar Sankaran for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) { 39574593a28SSravanthi Kollukuduru _dpu_crtc_setup_blend_cfg(mixer + lm_idx, 39674593a28SSravanthi Kollukuduru pstate, format); 39725fdd593SJeykumar Sankaran 39825fdd593SJeykumar Sankaran mixer[lm_idx].flush_mask |= flush_mask; 39925fdd593SJeykumar Sankaran 40025fdd593SJeykumar Sankaran if (bg_alpha_enable && !format->alpha_enable) 40125fdd593SJeykumar Sankaran mixer[lm_idx].mixer_op_mode = 0; 40225fdd593SJeykumar Sankaran else 40325fdd593SJeykumar Sankaran mixer[lm_idx].mixer_op_mode |= 40425fdd593SJeykumar Sankaran 1 << pstate->stage; 40525fdd593SJeykumar Sankaran } 40625fdd593SJeykumar Sankaran } 40725fdd593SJeykumar Sankaran 408b3652e87SKrishna Manikandan if (ctl->ops.set_active_pipes) 409b3652e87SKrishna Manikandan ctl->ops.set_active_pipes(ctl, fetch_active); 410b3652e87SKrishna Manikandan 41125fdd593SJeykumar Sankaran _dpu_crtc_program_lm_output_roi(crtc); 41225fdd593SJeykumar Sankaran } 41325fdd593SJeykumar Sankaran 41425fdd593SJeykumar Sankaran /** 41525fdd593SJeykumar Sankaran * _dpu_crtc_blend_setup - configure crtc mixers 41625fdd593SJeykumar Sankaran * @crtc: Pointer to drm crtc structure 41725fdd593SJeykumar Sankaran */ 41825fdd593SJeykumar Sankaran static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) 41925fdd593SJeykumar Sankaran { 42004b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 42104b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 42204b96b63SBruce Wang struct dpu_crtc_mixer *mixer = cstate->mixers; 42325fdd593SJeykumar Sankaran struct dpu_hw_ctl *ctl; 42425fdd593SJeykumar Sankaran struct dpu_hw_mixer *lm; 42553c064a1SDmitry Baryshkov struct dpu_hw_stage_cfg stage_cfg; 42625fdd593SJeykumar Sankaran int i; 42725fdd593SJeykumar Sankaran 4285b702d78SStephen Boyd DRM_DEBUG_ATOMIC("%s\n", dpu_crtc->name); 42925fdd593SJeykumar Sankaran 4309222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; i++) { 43125fdd593SJeykumar Sankaran mixer[i].mixer_op_mode = 0; 43225fdd593SJeykumar Sankaran mixer[i].flush_mask = 0; 433cf6916f4SJeykumar Sankaran if (mixer[i].lm_ctl->ops.clear_all_blendstages) 434cf6916f4SJeykumar Sankaran mixer[i].lm_ctl->ops.clear_all_blendstages( 435cf6916f4SJeykumar Sankaran mixer[i].lm_ctl); 43625fdd593SJeykumar Sankaran } 43725fdd593SJeykumar Sankaran 43825fdd593SJeykumar Sankaran /* initialize stage cfg */ 43953c064a1SDmitry Baryshkov memset(&stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg)); 44025fdd593SJeykumar Sankaran 44153c064a1SDmitry Baryshkov _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, &stage_cfg); 44225fdd593SJeykumar Sankaran 4439222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; i++) { 444cf6916f4SJeykumar Sankaran ctl = mixer[i].lm_ctl; 44525fdd593SJeykumar Sankaran lm = mixer[i].hw_lm; 44625fdd593SJeykumar Sankaran 44725fdd593SJeykumar Sankaran lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); 44825fdd593SJeykumar Sankaran 44925fdd593SJeykumar Sankaran mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl, 45025fdd593SJeykumar Sankaran mixer[i].hw_lm->idx); 45125fdd593SJeykumar Sankaran 45225fdd593SJeykumar Sankaran /* stage config flush mask */ 45325fdd593SJeykumar Sankaran ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); 45425fdd593SJeykumar Sankaran 4555b702d78SStephen Boyd DRM_DEBUG_ATOMIC("lm %d, op_mode 0x%X, ctl %d, flush mask 0x%x\n", 45625fdd593SJeykumar Sankaran mixer[i].hw_lm->idx - LM_0, 45725fdd593SJeykumar Sankaran mixer[i].mixer_op_mode, 45825fdd593SJeykumar Sankaran ctl->idx - CTL_0, 45925fdd593SJeykumar Sankaran mixer[i].flush_mask); 46025fdd593SJeykumar Sankaran 46125fdd593SJeykumar Sankaran ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, 46253c064a1SDmitry Baryshkov &stage_cfg); 46325fdd593SJeykumar Sankaran } 46425fdd593SJeykumar Sankaran } 46525fdd593SJeykumar Sankaran 46625fdd593SJeykumar Sankaran /** 46725fdd593SJeykumar Sankaran * _dpu_crtc_complete_flip - signal pending page_flip events 46825fdd593SJeykumar Sankaran * Any pending vblank events are added to the vblank_event_list 46925fdd593SJeykumar Sankaran * so that the next vblank interrupt shall signal them. 47025fdd593SJeykumar Sankaran * However PAGE_FLIP events are not handled through the vblank_event_list. 47125fdd593SJeykumar Sankaran * This API signals any pending PAGE_FLIP events requested through 47225fdd593SJeykumar Sankaran * DRM_IOCTL_MODE_PAGE_FLIP and are cached in the dpu_crtc->event. 47325fdd593SJeykumar Sankaran * @crtc: Pointer to drm crtc structure 47425fdd593SJeykumar Sankaran */ 47525fdd593SJeykumar Sankaran static void _dpu_crtc_complete_flip(struct drm_crtc *crtc) 47625fdd593SJeykumar Sankaran { 47725fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 47825fdd593SJeykumar Sankaran struct drm_device *dev = crtc->dev; 47925fdd593SJeykumar Sankaran unsigned long flags; 48025fdd593SJeykumar Sankaran 48125fdd593SJeykumar Sankaran spin_lock_irqsave(&dev->event_lock, flags); 48225fdd593SJeykumar Sankaran if (dpu_crtc->event) { 48325fdd593SJeykumar Sankaran DRM_DEBUG_VBL("%s: send event: %pK\n", dpu_crtc->name, 48425fdd593SJeykumar Sankaran dpu_crtc->event); 48525fdd593SJeykumar Sankaran trace_dpu_crtc_complete_flip(DRMID(crtc)); 48625fdd593SJeykumar Sankaran drm_crtc_send_vblank_event(crtc, dpu_crtc->event); 48725fdd593SJeykumar Sankaran dpu_crtc->event = NULL; 48825fdd593SJeykumar Sankaran } 48925fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dev->event_lock, flags); 49025fdd593SJeykumar Sankaran } 49125fdd593SJeykumar Sankaran 49225fdd593SJeykumar Sankaran enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) 49325fdd593SJeykumar Sankaran { 49425fdd593SJeykumar Sankaran struct drm_encoder *encoder; 49525fdd593SJeykumar Sankaran 496ab198a7aSSean Paul /* 497ab198a7aSSean Paul * TODO: This function is called from dpu debugfs and as part of atomic 498ab198a7aSSean Paul * check. When called from debugfs, the crtc->mutex must be held to 499ab198a7aSSean Paul * read crtc->state. However reading crtc->state from atomic check isn't 500ab198a7aSSean Paul * allowed (unless you have a good reason, a big comment, and a deep 501ab198a7aSSean Paul * understanding of how the atomic/modeset locks work (<- and this is 502ab198a7aSSean Paul * probably not possible)). So we'll keep the WARN_ON here for now, but 503ab198a7aSSean Paul * really we need to figure out a better way to track our operating mode 504ab198a7aSSean Paul */ 5051dfdb0e1SSean Paul WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 5061dfdb0e1SSean Paul 5074b8c6279SSean Paul /* TODO: Returns the first INTF_MODE, could there be multiple values? */ 5084b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 50925fdd593SJeykumar Sankaran return dpu_encoder_get_intf_mode(encoder); 51025fdd593SJeykumar Sankaran 51125fdd593SJeykumar Sankaran return INTF_MODE_NONE; 51225fdd593SJeykumar Sankaran } 51325fdd593SJeykumar Sankaran 514e4914867SSean Paul void dpu_crtc_vblank_callback(struct drm_crtc *crtc) 51525fdd593SJeykumar Sankaran { 51625fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 51725fdd593SJeykumar Sankaran 51825fdd593SJeykumar Sankaran /* keep statistics on vblank callback - with auto reset via debugfs */ 51925fdd593SJeykumar Sankaran if (ktime_compare(dpu_crtc->vblank_cb_time, ktime_set(0, 0)) == 0) 52025fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_time = ktime_get(); 52125fdd593SJeykumar Sankaran else 52225fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_count++; 52378d9b458SJessica Zhang 52478d9b458SJessica Zhang dpu_crtc_get_crc(crtc); 52578d9b458SJessica Zhang 52625fdd593SJeykumar Sankaran drm_crtc_handle_vblank(crtc); 52725fdd593SJeykumar Sankaran trace_dpu_crtc_vblank_cb(DRMID(crtc)); 52825fdd593SJeykumar Sankaran } 52925fdd593SJeykumar Sankaran 53025fdd593SJeykumar Sankaran static void dpu_crtc_frame_event_work(struct kthread_work *work) 53125fdd593SJeykumar Sankaran { 53204b96b63SBruce Wang struct dpu_crtc_frame_event *fevent = container_of(work, 53304b96b63SBruce Wang struct dpu_crtc_frame_event, work); 53404b96b63SBruce Wang struct drm_crtc *crtc = fevent->crtc; 53504b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 53625fdd593SJeykumar Sankaran unsigned long flags; 53725fdd593SJeykumar Sankaran bool frame_done = false; 53825fdd593SJeykumar Sankaran 53925fdd593SJeykumar Sankaran DPU_ATRACE_BEGIN("crtc_frame_event"); 54025fdd593SJeykumar Sankaran 5415b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event, 54225fdd593SJeykumar Sankaran ktime_to_ns(fevent->ts)); 54325fdd593SJeykumar Sankaran 54425fdd593SJeykumar Sankaran if (fevent->event & (DPU_ENCODER_FRAME_EVENT_DONE 54525fdd593SJeykumar Sankaran | DPU_ENCODER_FRAME_EVENT_ERROR 54625fdd593SJeykumar Sankaran | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { 54725fdd593SJeykumar Sankaran 54825fdd593SJeykumar Sankaran if (atomic_read(&dpu_crtc->frame_pending) < 1) { 54941a52059SRob Clark /* ignore vblank when not pending */ 55025fdd593SJeykumar Sankaran } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { 55125fdd593SJeykumar Sankaran /* release bandwidth and other resources */ 55225fdd593SJeykumar Sankaran trace_dpu_crtc_frame_event_done(DRMID(crtc), 55325fdd593SJeykumar Sankaran fevent->event); 554241b507cSRob Clark dpu_core_perf_crtc_release_bw(crtc); 55525fdd593SJeykumar Sankaran } else { 55625fdd593SJeykumar Sankaran trace_dpu_crtc_frame_event_more_pending(DRMID(crtc), 55725fdd593SJeykumar Sankaran fevent->event); 55825fdd593SJeykumar Sankaran } 55925fdd593SJeykumar Sankaran 56025fdd593SJeykumar Sankaran if (fevent->event & (DPU_ENCODER_FRAME_EVENT_DONE 56125fdd593SJeykumar Sankaran | DPU_ENCODER_FRAME_EVENT_ERROR)) 56225fdd593SJeykumar Sankaran frame_done = true; 56325fdd593SJeykumar Sankaran } 56425fdd593SJeykumar Sankaran 56525fdd593SJeykumar Sankaran if (fevent->event & DPU_ENCODER_FRAME_EVENT_PANEL_DEAD) 56625fdd593SJeykumar Sankaran DPU_ERROR("crtc%d ts:%lld received panel dead event\n", 56725fdd593SJeykumar Sankaran crtc->base.id, ktime_to_ns(fevent->ts)); 56825fdd593SJeykumar Sankaran 56925fdd593SJeykumar Sankaran if (frame_done) 57025fdd593SJeykumar Sankaran complete_all(&dpu_crtc->frame_done_comp); 57125fdd593SJeykumar Sankaran 57225fdd593SJeykumar Sankaran spin_lock_irqsave(&dpu_crtc->spin_lock, flags); 57325fdd593SJeykumar Sankaran list_add_tail(&fevent->list, &dpu_crtc->frame_event_list); 57425fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags); 57525fdd593SJeykumar Sankaran DPU_ATRACE_END("crtc_frame_event"); 57625fdd593SJeykumar Sankaran } 57725fdd593SJeykumar Sankaran 57825fdd593SJeykumar Sankaran /* 57925fdd593SJeykumar Sankaran * dpu_crtc_frame_event_cb - crtc frame event callback API. CRTC module 58025fdd593SJeykumar Sankaran * registers this API to encoder for all frame event callbacks like 58125fdd593SJeykumar Sankaran * frame_error, frame_done, idle_timeout, etc. Encoder may call different events 58225fdd593SJeykumar Sankaran * from different context - IRQ, user thread, commit_thread, etc. Each event 58325fdd593SJeykumar Sankaran * should be carefully reviewed and should be processed in proper task context 58425fdd593SJeykumar Sankaran * to avoid schedulin delay or properly manage the irq context's bottom half 58525fdd593SJeykumar Sankaran * processing. 58625fdd593SJeykumar Sankaran */ 58725fdd593SJeykumar Sankaran static void dpu_crtc_frame_event_cb(void *data, u32 event) 58825fdd593SJeykumar Sankaran { 58925fdd593SJeykumar Sankaran struct drm_crtc *crtc = (struct drm_crtc *)data; 59025fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc; 59125fdd593SJeykumar Sankaran struct msm_drm_private *priv; 59225fdd593SJeykumar Sankaran struct dpu_crtc_frame_event *fevent; 59325fdd593SJeykumar Sankaran unsigned long flags; 59425fdd593SJeykumar Sankaran u32 crtc_id; 59525fdd593SJeykumar Sankaran 59625fdd593SJeykumar Sankaran /* Nothing to do on idle event */ 59725fdd593SJeykumar Sankaran if (event & DPU_ENCODER_FRAME_EVENT_IDLE) 59825fdd593SJeykumar Sankaran return; 59925fdd593SJeykumar Sankaran 60025fdd593SJeykumar Sankaran dpu_crtc = to_dpu_crtc(crtc); 60125fdd593SJeykumar Sankaran priv = crtc->dev->dev_private; 60225fdd593SJeykumar Sankaran crtc_id = drm_crtc_index(crtc); 60325fdd593SJeykumar Sankaran 60425fdd593SJeykumar Sankaran trace_dpu_crtc_frame_event_cb(DRMID(crtc), event); 60525fdd593SJeykumar Sankaran 60625fdd593SJeykumar Sankaran spin_lock_irqsave(&dpu_crtc->spin_lock, flags); 60725fdd593SJeykumar Sankaran fevent = list_first_entry_or_null(&dpu_crtc->frame_event_list, 60825fdd593SJeykumar Sankaran struct dpu_crtc_frame_event, list); 60925fdd593SJeykumar Sankaran if (fevent) 61025fdd593SJeykumar Sankaran list_del_init(&fevent->list); 61125fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags); 61225fdd593SJeykumar Sankaran 61325fdd593SJeykumar Sankaran if (!fevent) { 6145e16372bSRob Clark DRM_ERROR_RATELIMITED("crtc%d event %d overflow\n", crtc->base.id, event); 61525fdd593SJeykumar Sankaran return; 61625fdd593SJeykumar Sankaran } 61725fdd593SJeykumar Sankaran 61825fdd593SJeykumar Sankaran fevent->event = event; 61925fdd593SJeykumar Sankaran fevent->crtc = crtc; 62025fdd593SJeykumar Sankaran fevent->ts = ktime_get(); 6211041dee2SBernard kthread_queue_work(priv->event_thread[crtc_id].worker, &fevent->work); 62225fdd593SJeykumar Sankaran } 62325fdd593SJeykumar Sankaran 62480b4b4a7SRob Clark void dpu_crtc_complete_commit(struct drm_crtc *crtc) 62525fdd593SJeykumar Sankaran { 62625fdd593SJeykumar Sankaran trace_dpu_crtc_complete_commit(DRMID(crtc)); 627a1f2ba60SKrishna Manikandan dpu_core_perf_crtc_update(crtc, 0, false); 628fd630ae9SRob Clark _dpu_crtc_complete_flip(crtc); 62925fdd593SJeykumar Sankaran } 63025fdd593SJeykumar Sankaran 63125fdd593SJeykumar Sankaran static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, 63225fdd593SJeykumar Sankaran struct drm_crtc_state *state) 63325fdd593SJeykumar Sankaran { 63404b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); 63504b96b63SBruce Wang struct drm_display_mode *adj_mode = &state->adjusted_mode; 6363804a982SJordan Crouse u32 crtc_split_width = adj_mode->hdisplay / cstate->num_mixers; 63725fdd593SJeykumar Sankaran int i; 63825fdd593SJeykumar Sankaran 6399222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; i++) { 64025fdd593SJeykumar Sankaran struct drm_rect *r = &cstate->lm_bounds[i]; 64125fdd593SJeykumar Sankaran r->x1 = crtc_split_width * i; 64225fdd593SJeykumar Sankaran r->y1 = 0; 64325fdd593SJeykumar Sankaran r->x2 = r->x1 + crtc_split_width; 64435d600ddSJordan Crouse r->y2 = adj_mode->vdisplay; 64525fdd593SJeykumar Sankaran 64625fdd593SJeykumar Sankaran trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r); 64725fdd593SJeykumar Sankaran } 64825fdd593SJeykumar Sankaran } 64925fdd593SJeykumar Sankaran 6504259ff7aSKalyan Thota static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, 6514259ff7aSKalyan Thota struct dpu_hw_pcc_cfg *cfg) 6524259ff7aSKalyan Thota { 6534259ff7aSKalyan Thota struct drm_color_ctm *ctm; 6544259ff7aSKalyan Thota 6554259ff7aSKalyan Thota memset(cfg, 0, sizeof(struct dpu_hw_pcc_cfg)); 6564259ff7aSKalyan Thota 6574259ff7aSKalyan Thota ctm = (struct drm_color_ctm *)state->ctm->data; 6584259ff7aSKalyan Thota 6594259ff7aSKalyan Thota if (!ctm) 6604259ff7aSKalyan Thota return; 6614259ff7aSKalyan Thota 6624259ff7aSKalyan Thota cfg->r.r = CONVERT_S3_15(ctm->matrix[0]); 6634259ff7aSKalyan Thota cfg->g.r = CONVERT_S3_15(ctm->matrix[1]); 6644259ff7aSKalyan Thota cfg->b.r = CONVERT_S3_15(ctm->matrix[2]); 6654259ff7aSKalyan Thota 6664259ff7aSKalyan Thota cfg->r.g = CONVERT_S3_15(ctm->matrix[3]); 6674259ff7aSKalyan Thota cfg->g.g = CONVERT_S3_15(ctm->matrix[4]); 6684259ff7aSKalyan Thota cfg->b.g = CONVERT_S3_15(ctm->matrix[5]); 6694259ff7aSKalyan Thota 6704259ff7aSKalyan Thota cfg->r.b = CONVERT_S3_15(ctm->matrix[6]); 6714259ff7aSKalyan Thota cfg->g.b = CONVERT_S3_15(ctm->matrix[7]); 6724259ff7aSKalyan Thota cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); 6734259ff7aSKalyan Thota } 6744259ff7aSKalyan Thota 6754259ff7aSKalyan Thota static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) 6764259ff7aSKalyan Thota { 6774259ff7aSKalyan Thota struct drm_crtc_state *state = crtc->state; 6784259ff7aSKalyan Thota struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 6794259ff7aSKalyan Thota struct dpu_crtc_mixer *mixer = cstate->mixers; 6804259ff7aSKalyan Thota struct dpu_hw_pcc_cfg cfg; 6814259ff7aSKalyan Thota struct dpu_hw_ctl *ctl; 6824259ff7aSKalyan Thota struct dpu_hw_dspp *dspp; 6834259ff7aSKalyan Thota int i; 6844259ff7aSKalyan Thota 6854259ff7aSKalyan Thota 6864259ff7aSKalyan Thota if (!state->color_mgmt_changed) 6874259ff7aSKalyan Thota return; 6884259ff7aSKalyan Thota 6894259ff7aSKalyan Thota for (i = 0; i < cstate->num_mixers; i++) { 6904259ff7aSKalyan Thota ctl = mixer[i].lm_ctl; 6914259ff7aSKalyan Thota dspp = mixer[i].hw_dspp; 6924259ff7aSKalyan Thota 6934259ff7aSKalyan Thota if (!dspp || !dspp->ops.setup_pcc) 6944259ff7aSKalyan Thota continue; 6954259ff7aSKalyan Thota 6964259ff7aSKalyan Thota if (!state->ctm) { 6974259ff7aSKalyan Thota dspp->ops.setup_pcc(dspp, NULL); 6984259ff7aSKalyan Thota } else { 6994259ff7aSKalyan Thota _dpu_crtc_get_pcc_coeff(state, &cfg); 7004259ff7aSKalyan Thota dspp->ops.setup_pcc(dspp, &cfg); 7014259ff7aSKalyan Thota } 7024259ff7aSKalyan Thota 7034259ff7aSKalyan Thota mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, 7044259ff7aSKalyan Thota mixer[i].hw_dspp->idx); 7054259ff7aSKalyan Thota 7064259ff7aSKalyan Thota /* stage config flush mask */ 7074259ff7aSKalyan Thota ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); 7084259ff7aSKalyan Thota 7095b702d78SStephen Boyd DRM_DEBUG_ATOMIC("lm %d, ctl %d, flush mask 0x%x\n", 7104259ff7aSKalyan Thota mixer[i].hw_lm->idx - DSPP_0, 7114259ff7aSKalyan Thota ctl->idx - CTL_0, 7124259ff7aSKalyan Thota mixer[i].flush_mask); 7134259ff7aSKalyan Thota } 7144259ff7aSKalyan Thota } 7154259ff7aSKalyan Thota 71625fdd593SJeykumar Sankaran static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, 717f6ebe9f9SMaxime Ripard struct drm_atomic_state *state) 71825fdd593SJeykumar Sankaran { 719e12e5263SRob Clark struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 72025fdd593SJeykumar Sankaran struct drm_encoder *encoder; 72125fdd593SJeykumar Sankaran 72225fdd593SJeykumar Sankaran if (!crtc->state->enable) { 7235b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d -> enable %d, skip atomic_begin\n", 72425fdd593SJeykumar Sankaran crtc->base.id, crtc->state->enable); 72525fdd593SJeykumar Sankaran return; 72625fdd593SJeykumar Sankaran } 72725fdd593SJeykumar Sankaran 7285b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d\n", crtc->base.id); 72925fdd593SJeykumar Sankaran 73025fdd593SJeykumar Sankaran _dpu_crtc_setup_lm_bounds(crtc, crtc->state); 73125fdd593SJeykumar Sankaran 73225fdd593SJeykumar Sankaran /* encoder will trigger pending mask now */ 7334b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 73425fdd593SJeykumar Sankaran dpu_encoder_trigger_kickoff_pending(encoder); 73525fdd593SJeykumar Sankaran 73625fdd593SJeykumar Sankaran /* 73725fdd593SJeykumar Sankaran * If no mixers have been allocated in dpu_crtc_atomic_check(), 73825fdd593SJeykumar Sankaran * it means we are trying to flush a CRTC whose state is disabled: 73925fdd593SJeykumar Sankaran * nothing else needs to be done. 74025fdd593SJeykumar Sankaran */ 7419222cdd2SJeykumar Sankaran if (unlikely(!cstate->num_mixers)) 74225fdd593SJeykumar Sankaran return; 74325fdd593SJeykumar Sankaran 74425fdd593SJeykumar Sankaran _dpu_crtc_blend_setup(crtc); 74525fdd593SJeykumar Sankaran 7464259ff7aSKalyan Thota _dpu_crtc_setup_cp_blocks(crtc); 7474259ff7aSKalyan Thota 74825fdd593SJeykumar Sankaran /* 74925fdd593SJeykumar Sankaran * PP_DONE irq is only used by command mode for now. 75025fdd593SJeykumar Sankaran * It is better to request pending before FLUSH and START trigger 75125fdd593SJeykumar Sankaran * to make sure no pp_done irq missed. 75225fdd593SJeykumar Sankaran * This is safe because no pp_done will happen before SW trigger 75325fdd593SJeykumar Sankaran * in command mode. 75425fdd593SJeykumar Sankaran */ 75525fdd593SJeykumar Sankaran } 75625fdd593SJeykumar Sankaran 75725fdd593SJeykumar Sankaran static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, 758f6ebe9f9SMaxime Ripard struct drm_atomic_state *state) 75925fdd593SJeykumar Sankaran { 76025fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc; 76125fdd593SJeykumar Sankaran struct drm_device *dev; 76225fdd593SJeykumar Sankaran struct drm_plane *plane; 76325fdd593SJeykumar Sankaran struct msm_drm_private *priv; 76425fdd593SJeykumar Sankaran unsigned long flags; 76525fdd593SJeykumar Sankaran struct dpu_crtc_state *cstate; 76625fdd593SJeykumar Sankaran 76725fdd593SJeykumar Sankaran if (!crtc->state->enable) { 7685b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d -> enable %d, skip atomic_flush\n", 76925fdd593SJeykumar Sankaran crtc->base.id, crtc->state->enable); 77025fdd593SJeykumar Sankaran return; 77125fdd593SJeykumar Sankaran } 77225fdd593SJeykumar Sankaran 7735b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d\n", crtc->base.id); 77425fdd593SJeykumar Sankaran 77525fdd593SJeykumar Sankaran dpu_crtc = to_dpu_crtc(crtc); 77625fdd593SJeykumar Sankaran cstate = to_dpu_crtc_state(crtc->state); 77725fdd593SJeykumar Sankaran dev = crtc->dev; 77825fdd593SJeykumar Sankaran priv = dev->dev_private; 77925fdd593SJeykumar Sankaran 78025fdd593SJeykumar Sankaran if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { 78125fdd593SJeykumar Sankaran DPU_ERROR("invalid crtc index[%d]\n", crtc->index); 78225fdd593SJeykumar Sankaran return; 78325fdd593SJeykumar Sankaran } 78425fdd593SJeykumar Sankaran 785e12e5263SRob Clark WARN_ON(dpu_crtc->event); 78625fdd593SJeykumar Sankaran spin_lock_irqsave(&dev->event_lock, flags); 78725fdd593SJeykumar Sankaran dpu_crtc->event = crtc->state->event; 78825fdd593SJeykumar Sankaran crtc->state->event = NULL; 78925fdd593SJeykumar Sankaran spin_unlock_irqrestore(&dev->event_lock, flags); 79025fdd593SJeykumar Sankaran 79125fdd593SJeykumar Sankaran /* 79225fdd593SJeykumar Sankaran * If no mixers has been allocated in dpu_crtc_atomic_check(), 79325fdd593SJeykumar Sankaran * it means we are trying to flush a CRTC whose state is disabled: 79425fdd593SJeykumar Sankaran * nothing else needs to be done. 79525fdd593SJeykumar Sankaran */ 7969222cdd2SJeykumar Sankaran if (unlikely(!cstate->num_mixers)) 79725fdd593SJeykumar Sankaran return; 79825fdd593SJeykumar Sankaran 79925fdd593SJeykumar Sankaran /* update performance setting before crtc kickoff */ 80025fdd593SJeykumar Sankaran dpu_core_perf_crtc_update(crtc, 1, false); 80125fdd593SJeykumar Sankaran 80225fdd593SJeykumar Sankaran /* 80325fdd593SJeykumar Sankaran * Final plane updates: Give each plane a chance to complete all 80425fdd593SJeykumar Sankaran * required writes/flushing before crtc's "flush 80525fdd593SJeykumar Sankaran * everything" call below. 80625fdd593SJeykumar Sankaran */ 80725fdd593SJeykumar Sankaran drm_atomic_crtc_for_each_plane(plane, crtc) { 80825fdd593SJeykumar Sankaran if (dpu_crtc->smmu_state.transition_error) 80925fdd593SJeykumar Sankaran dpu_plane_set_error(plane, true); 81025fdd593SJeykumar Sankaran dpu_plane_flush(plane); 81125fdd593SJeykumar Sankaran } 81225fdd593SJeykumar Sankaran 81325fdd593SJeykumar Sankaran /* Kickoff will be scheduled by outer layer */ 81425fdd593SJeykumar Sankaran } 81525fdd593SJeykumar Sankaran 81625fdd593SJeykumar Sankaran /** 81725fdd593SJeykumar Sankaran * dpu_crtc_destroy_state - state destroy hook 81825fdd593SJeykumar Sankaran * @crtc: drm CRTC 81925fdd593SJeykumar Sankaran * @state: CRTC state object to release 82025fdd593SJeykumar Sankaran */ 82125fdd593SJeykumar Sankaran static void dpu_crtc_destroy_state(struct drm_crtc *crtc, 82225fdd593SJeykumar Sankaran struct drm_crtc_state *state) 82325fdd593SJeykumar Sankaran { 824e12e5263SRob Clark struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); 82525fdd593SJeykumar Sankaran 8265b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d\n", crtc->base.id); 82725fdd593SJeykumar Sankaran 82825fdd593SJeykumar Sankaran __drm_atomic_helper_crtc_destroy_state(state); 82925fdd593SJeykumar Sankaran 83025fdd593SJeykumar Sankaran kfree(cstate); 83125fdd593SJeykumar Sankaran } 83225fdd593SJeykumar Sankaran 83325fdd593SJeykumar Sankaran static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) 83425fdd593SJeykumar Sankaran { 83504b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 83625fdd593SJeykumar Sankaran int ret, rc = 0; 83725fdd593SJeykumar Sankaran 83825fdd593SJeykumar Sankaran if (!atomic_read(&dpu_crtc->frame_pending)) { 8395b702d78SStephen Boyd DRM_DEBUG_ATOMIC("no frames pending\n"); 84025fdd593SJeykumar Sankaran return 0; 84125fdd593SJeykumar Sankaran } 84225fdd593SJeykumar Sankaran 84325fdd593SJeykumar Sankaran DPU_ATRACE_BEGIN("frame done completion wait"); 84425fdd593SJeykumar Sankaran ret = wait_for_completion_timeout(&dpu_crtc->frame_done_comp, 84570df9610SSean Paul msecs_to_jiffies(DPU_CRTC_FRAME_DONE_TIMEOUT_MS)); 84625fdd593SJeykumar Sankaran if (!ret) { 84725fdd593SJeykumar Sankaran DRM_ERROR("frame done wait timed out, ret:%d\n", ret); 84825fdd593SJeykumar Sankaran rc = -ETIMEDOUT; 84925fdd593SJeykumar Sankaran } 85025fdd593SJeykumar Sankaran DPU_ATRACE_END("frame done completion wait"); 85125fdd593SJeykumar Sankaran 85225fdd593SJeykumar Sankaran return rc; 85325fdd593SJeykumar Sankaran } 85425fdd593SJeykumar Sankaran 855b4bb9f15SRob Clark void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) 85625fdd593SJeykumar Sankaran { 85725fdd593SJeykumar Sankaran struct drm_encoder *encoder; 85804b96b63SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 85904b96b63SBruce Wang struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); 86004b96b63SBruce Wang struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 86125fdd593SJeykumar Sankaran 86225fdd593SJeykumar Sankaran /* 86325fdd593SJeykumar Sankaran * If no mixers has been allocated in dpu_crtc_atomic_check(), 86425fdd593SJeykumar Sankaran * it means we are trying to start a CRTC whose state is disabled: 86525fdd593SJeykumar Sankaran * nothing else needs to be done. 86625fdd593SJeykumar Sankaran */ 8679222cdd2SJeykumar Sankaran if (unlikely(!cstate->num_mixers)) 86825fdd593SJeykumar Sankaran return; 86925fdd593SJeykumar Sankaran 87025fdd593SJeykumar Sankaran DPU_ATRACE_BEGIN("crtc_commit"); 87125fdd593SJeykumar Sankaran 87225fdd593SJeykumar Sankaran /* 8734b8c6279SSean Paul * Encoder will flush/start now, unless it has a tx pending. If so, it 8744b8c6279SSean Paul * may delay and flush at an irq event (e.g. ppdone) 87525fdd593SJeykumar Sankaran */ 8764b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, 877d3db61caSBruce Wang crtc->state->encoder_mask) 8780c91ed51SRob Clark dpu_encoder_prepare_for_kickoff(encoder); 87950bcc689SSean Paul 88025fdd593SJeykumar Sankaran if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { 88125fdd593SJeykumar Sankaran /* acquire bandwidth and other resources */ 8825b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d first commit\n", crtc->base.id); 88325fdd593SJeykumar Sankaran } else 8845b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d commit\n", crtc->base.id); 88525fdd593SJeykumar Sankaran 88625fdd593SJeykumar Sankaran dpu_crtc->play_count++; 88725fdd593SJeykumar Sankaran 88825fdd593SJeykumar Sankaran dpu_vbif_clear_errors(dpu_kms); 88925fdd593SJeykumar Sankaran 8904b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 891b4bb9f15SRob Clark dpu_encoder_kickoff(encoder); 89225fdd593SJeykumar Sankaran 89325fdd593SJeykumar Sankaran reinit_completion(&dpu_crtc->frame_done_comp); 89425fdd593SJeykumar Sankaran DPU_ATRACE_END("crtc_commit"); 89525fdd593SJeykumar Sankaran } 89625fdd593SJeykumar Sankaran 897ff5952a7SSean Paul static void dpu_crtc_reset(struct drm_crtc *crtc) 89825fdd593SJeykumar Sankaran { 8991cff7440SMaarten Lankhorst struct dpu_crtc_state *cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); 90025fdd593SJeykumar Sankaran 901ff5952a7SSean Paul if (crtc->state) 902ff5952a7SSean Paul dpu_crtc_destroy_state(crtc, crtc->state); 90325fdd593SJeykumar Sankaran 9041cff7440SMaarten Lankhorst __drm_atomic_helper_crtc_reset(crtc, &cstate->base); 90525fdd593SJeykumar Sankaran } 90625fdd593SJeykumar Sankaran 90725fdd593SJeykumar Sankaran /** 90825fdd593SJeykumar Sankaran * dpu_crtc_duplicate_state - state duplicate hook 90925fdd593SJeykumar Sankaran * @crtc: Pointer to drm crtc structure 91025fdd593SJeykumar Sankaran */ 91125fdd593SJeykumar Sankaran static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) 91225fdd593SJeykumar Sankaran { 913e12e5263SRob Clark struct dpu_crtc_state *cstate, *old_cstate = to_dpu_crtc_state(crtc->state); 91425fdd593SJeykumar Sankaran 91525fdd593SJeykumar Sankaran cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); 91625fdd593SJeykumar Sankaran if (!cstate) { 91725fdd593SJeykumar Sankaran DPU_ERROR("failed to allocate state\n"); 91825fdd593SJeykumar Sankaran return NULL; 91925fdd593SJeykumar Sankaran } 92025fdd593SJeykumar Sankaran 92125fdd593SJeykumar Sankaran /* duplicate base helper */ 92225fdd593SJeykumar Sankaran __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); 92325fdd593SJeykumar Sankaran 92425fdd593SJeykumar Sankaran return &cstate->base; 92525fdd593SJeykumar Sankaran } 92625fdd593SJeykumar Sankaran 927f7aafc8dSSean Paul static void dpu_crtc_disable(struct drm_crtc *crtc, 928351f950dSMaxime Ripard struct drm_atomic_state *state) 92925fdd593SJeykumar Sankaran { 930351f950dSMaxime Ripard struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, 931351f950dSMaxime Ripard crtc); 932e12e5263SRob Clark struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 933e12e5263SRob Clark struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); 93425fdd593SJeykumar Sankaran struct drm_encoder *encoder; 9352f2eb723SRajesh Yadav unsigned long flags; 936241b507cSRob Clark bool release_bandwidth = false; 93725fdd593SJeykumar Sankaran 93825fdd593SJeykumar Sankaran DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); 93925fdd593SJeykumar Sankaran 9402f2eb723SRajesh Yadav /* Disable/save vblank irq handling */ 9412f2eb723SRajesh Yadav drm_crtc_vblank_off(crtc); 9422f2eb723SRajesh Yadav 943a796ba2cSSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, 944241b507cSRob Clark old_crtc_state->encoder_mask) { 945241b507cSRob Clark /* in video mode, we hold an extra bandwidth reference 946241b507cSRob Clark * as we cannot drop bandwidth at frame-done if any 947241b507cSRob Clark * crtc is being used in video mode. 948241b507cSRob Clark */ 949241b507cSRob Clark if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) 950241b507cSRob Clark release_bandwidth = true; 951a796ba2cSSean Paul dpu_encoder_assign_crtc(encoder, NULL); 952241b507cSRob Clark } 95325fdd593SJeykumar Sankaran 95425fdd593SJeykumar Sankaran /* wait for frame_event_done completion */ 95525fdd593SJeykumar Sankaran if (_dpu_crtc_wait_for_frame_done(crtc)) 95625fdd593SJeykumar Sankaran DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", 95725fdd593SJeykumar Sankaran crtc->base.id, 95825fdd593SJeykumar Sankaran atomic_read(&dpu_crtc->frame_pending)); 95925fdd593SJeykumar Sankaran 96025fdd593SJeykumar Sankaran trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); 96125fdd593SJeykumar Sankaran dpu_crtc->enabled = false; 96225fdd593SJeykumar Sankaran 96325fdd593SJeykumar Sankaran if (atomic_read(&dpu_crtc->frame_pending)) { 96425fdd593SJeykumar Sankaran trace_dpu_crtc_disable_frame_pending(DRMID(crtc), 96525fdd593SJeykumar Sankaran atomic_read(&dpu_crtc->frame_pending)); 966241b507cSRob Clark if (release_bandwidth) 96725fdd593SJeykumar Sankaran dpu_core_perf_crtc_release_bw(crtc); 96825fdd593SJeykumar Sankaran atomic_set(&dpu_crtc->frame_pending, 0); 96925fdd593SJeykumar Sankaran } 97025fdd593SJeykumar Sankaran 97125fdd593SJeykumar Sankaran dpu_core_perf_crtc_update(crtc, 0, true); 97225fdd593SJeykumar Sankaran 9734b8c6279SSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 97425fdd593SJeykumar Sankaran dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); 97525fdd593SJeykumar Sankaran 9769222cdd2SJeykumar Sankaran memset(cstate->mixers, 0, sizeof(cstate->mixers)); 9779222cdd2SJeykumar Sankaran cstate->num_mixers = 0; 97825fdd593SJeykumar Sankaran 97925fdd593SJeykumar Sankaran /* disable clk & bw control until clk & bw properties are set */ 98025fdd593SJeykumar Sankaran cstate->bw_control = false; 98125fdd593SJeykumar Sankaran cstate->bw_split_vote = false; 98225fdd593SJeykumar Sankaran 9832f2eb723SRajesh Yadav if (crtc->state->event && !crtc->state->active) { 9842f2eb723SRajesh Yadav spin_lock_irqsave(&crtc->dev->event_lock, flags); 9852f2eb723SRajesh Yadav drm_crtc_send_vblank_event(crtc, crtc->state->event); 9862f2eb723SRajesh Yadav crtc->state->event = NULL; 9872f2eb723SRajesh Yadav spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 9882f2eb723SRajesh Yadav } 989b77d0f0dSSean Paul 990b77d0f0dSSean Paul pm_runtime_put_sync(crtc->dev->dev); 99125fdd593SJeykumar Sankaran } 99225fdd593SJeykumar Sankaran 99325fdd593SJeykumar Sankaran static void dpu_crtc_enable(struct drm_crtc *crtc, 994351f950dSMaxime Ripard struct drm_atomic_state *state) 99525fdd593SJeykumar Sankaran { 996e12e5263SRob Clark struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 99725fdd593SJeykumar Sankaran struct drm_encoder *encoder; 99835c719daSRob Clark bool request_bandwidth = false; 99925fdd593SJeykumar Sankaran 1000b77d0f0dSSean Paul pm_runtime_get_sync(crtc->dev->dev); 1001b77d0f0dSSean Paul 100225fdd593SJeykumar Sankaran DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); 100325fdd593SJeykumar Sankaran 1004241b507cSRob Clark drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { 1005241b507cSRob Clark /* in video mode, we hold an extra bandwidth reference 1006241b507cSRob Clark * as we cannot drop bandwidth at frame-done if any 1007241b507cSRob Clark * crtc is being used in video mode. 1008241b507cSRob Clark */ 1009241b507cSRob Clark if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) 1010241b507cSRob Clark request_bandwidth = true; 101125fdd593SJeykumar Sankaran dpu_encoder_register_frame_event_callback(encoder, 101225fdd593SJeykumar Sankaran dpu_crtc_frame_event_cb, (void *)crtc); 1013241b507cSRob Clark } 1014241b507cSRob Clark 1015241b507cSRob Clark if (request_bandwidth) 1016241b507cSRob Clark atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); 101725fdd593SJeykumar Sankaran 101825fdd593SJeykumar Sankaran trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); 101925fdd593SJeykumar Sankaran dpu_crtc->enabled = true; 102025fdd593SJeykumar Sankaran 1021a796ba2cSSean Paul drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) 1022a796ba2cSSean Paul dpu_encoder_assign_crtc(encoder, crtc); 102325fdd593SJeykumar Sankaran 10242f2eb723SRajesh Yadav /* Enable/restore vblank irq handling */ 10252f2eb723SRajesh Yadav drm_crtc_vblank_on(crtc); 102625fdd593SJeykumar Sankaran } 102725fdd593SJeykumar Sankaran 102825fdd593SJeykumar Sankaran struct plane_state { 102925fdd593SJeykumar Sankaran struct dpu_plane_state *dpu_pstate; 103025fdd593SJeykumar Sankaran const struct drm_plane_state *drm_pstate; 103125fdd593SJeykumar Sankaran int stage; 103225fdd593SJeykumar Sankaran u32 pipe_id; 103325fdd593SJeykumar Sankaran }; 103425fdd593SJeykumar Sankaran 103525fdd593SJeykumar Sankaran static int dpu_crtc_atomic_check(struct drm_crtc *crtc, 103629b77ad7SMaxime Ripard struct drm_atomic_state *state) 103725fdd593SJeykumar Sankaran { 103829b77ad7SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, 103929b77ad7SMaxime Ripard crtc); 1040e12e5263SRob Clark struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 104129b77ad7SMaxime Ripard struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc_state); 104225fdd593SJeykumar Sankaran struct plane_state *pstates; 104325fdd593SJeykumar Sankaran 104425fdd593SJeykumar Sankaran const struct drm_plane_state *pstate; 104525fdd593SJeykumar Sankaran struct drm_plane *plane; 104625fdd593SJeykumar Sankaran struct drm_display_mode *mode; 104725fdd593SJeykumar Sankaran 104822f76094SStephen Boyd int cnt = 0, rc = 0, mixer_width = 0, i, z_pos; 104925fdd593SJeykumar Sankaran 105025fdd593SJeykumar Sankaran struct dpu_multirect_plane_states multirect_plane[DPU_STAGE_MAX * 2]; 105125fdd593SJeykumar Sankaran int multirect_count = 0; 105225fdd593SJeykumar Sankaran const struct drm_plane_state *pipe_staged[SSPP_MAX]; 105325fdd593SJeykumar Sankaran int left_zpos_cnt = 0, right_zpos_cnt = 0; 105425fdd593SJeykumar Sankaran struct drm_rect crtc_rect = { 0 }; 105525fdd593SJeykumar Sankaran 105625fdd593SJeykumar Sankaran pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL); 105725fdd593SJeykumar Sankaran 105829b77ad7SMaxime Ripard if (!crtc_state->enable || !crtc_state->active) { 10595b702d78SStephen Boyd DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n", 106029b77ad7SMaxime Ripard crtc->base.id, crtc_state->enable, 106129b77ad7SMaxime Ripard crtc_state->active); 1062a29c8c02SKalyan Thota memset(&cstate->new_perf, 0, sizeof(cstate->new_perf)); 106325fdd593SJeykumar Sankaran goto end; 106425fdd593SJeykumar Sankaran } 106525fdd593SJeykumar Sankaran 106629b77ad7SMaxime Ripard mode = &crtc_state->adjusted_mode; 10675b702d78SStephen Boyd DRM_DEBUG_ATOMIC("%s: check\n", dpu_crtc->name); 106825fdd593SJeykumar Sankaran 106925fdd593SJeykumar Sankaran /* force a full mode set if active state changed */ 107029b77ad7SMaxime Ripard if (crtc_state->active_changed) 107129b77ad7SMaxime Ripard crtc_state->mode_changed = true; 107225fdd593SJeykumar Sankaran 107325fdd593SJeykumar Sankaran memset(pipe_staged, 0, sizeof(pipe_staged)); 107425fdd593SJeykumar Sankaran 107522f76094SStephen Boyd if (cstate->num_mixers) { 10763804a982SJordan Crouse mixer_width = mode->hdisplay / cstate->num_mixers; 107725fdd593SJeykumar Sankaran 107829b77ad7SMaxime Ripard _dpu_crtc_setup_lm_bounds(crtc, crtc_state); 107922f76094SStephen Boyd } 108025fdd593SJeykumar Sankaran 108125fdd593SJeykumar Sankaran crtc_rect.x2 = mode->hdisplay; 108225fdd593SJeykumar Sankaran crtc_rect.y2 = mode->vdisplay; 108325fdd593SJeykumar Sankaran 108425fdd593SJeykumar Sankaran /* get plane state for all drm planes associated with crtc state */ 108529b77ad7SMaxime Ripard drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) { 108625fdd593SJeykumar Sankaran struct drm_rect dst, clip = crtc_rect; 108725fdd593SJeykumar Sankaran 108825fdd593SJeykumar Sankaran if (IS_ERR_OR_NULL(pstate)) { 108925fdd593SJeykumar Sankaran rc = PTR_ERR(pstate); 109025fdd593SJeykumar Sankaran DPU_ERROR("%s: failed to get plane%d state, %d\n", 109125fdd593SJeykumar Sankaran dpu_crtc->name, plane->base.id, rc); 109225fdd593SJeykumar Sankaran goto end; 109325fdd593SJeykumar Sankaran } 109425fdd593SJeykumar Sankaran if (cnt >= DPU_STAGE_MAX * 4) 109525fdd593SJeykumar Sankaran continue; 109625fdd593SJeykumar Sankaran 109725fdd593SJeykumar Sankaran pstates[cnt].dpu_pstate = to_dpu_plane_state(pstate); 109825fdd593SJeykumar Sankaran pstates[cnt].drm_pstate = pstate; 109925fdd593SJeykumar Sankaran pstates[cnt].stage = pstate->normalized_zpos; 110025fdd593SJeykumar Sankaran pstates[cnt].pipe_id = dpu_plane_pipe(plane); 110125fdd593SJeykumar Sankaran 110225fdd593SJeykumar Sankaran if (pipe_staged[pstates[cnt].pipe_id]) { 110325fdd593SJeykumar Sankaran multirect_plane[multirect_count].r0 = 110425fdd593SJeykumar Sankaran pipe_staged[pstates[cnt].pipe_id]; 110525fdd593SJeykumar Sankaran multirect_plane[multirect_count].r1 = pstate; 110625fdd593SJeykumar Sankaran multirect_count++; 110725fdd593SJeykumar Sankaran 110825fdd593SJeykumar Sankaran pipe_staged[pstates[cnt].pipe_id] = NULL; 110925fdd593SJeykumar Sankaran } else { 111025fdd593SJeykumar Sankaran pipe_staged[pstates[cnt].pipe_id] = pstate; 111125fdd593SJeykumar Sankaran } 111225fdd593SJeykumar Sankaran 111325fdd593SJeykumar Sankaran cnt++; 111425fdd593SJeykumar Sankaran 111525fdd593SJeykumar Sankaran dst = drm_plane_state_dest(pstate); 111696fc56a7SSean Paul if (!drm_rect_intersect(&clip, &dst)) { 111725fdd593SJeykumar Sankaran DPU_ERROR("invalid vertical/horizontal destination\n"); 111825fdd593SJeykumar Sankaran DPU_ERROR("display: " DRM_RECT_FMT " plane: " 111925fdd593SJeykumar Sankaran DRM_RECT_FMT "\n", DRM_RECT_ARG(&crtc_rect), 112025fdd593SJeykumar Sankaran DRM_RECT_ARG(&dst)); 112125fdd593SJeykumar Sankaran rc = -E2BIG; 112225fdd593SJeykumar Sankaran goto end; 112325fdd593SJeykumar Sankaran } 112425fdd593SJeykumar Sankaran } 112525fdd593SJeykumar Sankaran 112625fdd593SJeykumar Sankaran for (i = 1; i < SSPP_MAX; i++) { 112725fdd593SJeykumar Sankaran if (pipe_staged[i]) { 112825fdd593SJeykumar Sankaran dpu_plane_clear_multirect(pipe_staged[i]); 112925fdd593SJeykumar Sankaran 113025fdd593SJeykumar Sankaran if (is_dpu_plane_virtual(pipe_staged[i]->plane)) { 113125fdd593SJeykumar Sankaran DPU_ERROR( 113225fdd593SJeykumar Sankaran "r1 only virt plane:%d not supported\n", 113325fdd593SJeykumar Sankaran pipe_staged[i]->plane->base.id); 113425fdd593SJeykumar Sankaran rc = -EINVAL; 113525fdd593SJeykumar Sankaran goto end; 113625fdd593SJeykumar Sankaran } 113725fdd593SJeykumar Sankaran } 113825fdd593SJeykumar Sankaran } 113925fdd593SJeykumar Sankaran 114025fdd593SJeykumar Sankaran z_pos = -1; 114125fdd593SJeykumar Sankaran for (i = 0; i < cnt; i++) { 114225fdd593SJeykumar Sankaran /* reset counts at every new blend stage */ 114325fdd593SJeykumar Sankaran if (pstates[i].stage != z_pos) { 114425fdd593SJeykumar Sankaran left_zpos_cnt = 0; 114525fdd593SJeykumar Sankaran right_zpos_cnt = 0; 114625fdd593SJeykumar Sankaran z_pos = pstates[i].stage; 114725fdd593SJeykumar Sankaran } 114825fdd593SJeykumar Sankaran 114925fdd593SJeykumar Sankaran /* verify z_pos setting before using it */ 115025fdd593SJeykumar Sankaran if (z_pos >= DPU_STAGE_MAX - DPU_STAGE_0) { 115125fdd593SJeykumar Sankaran DPU_ERROR("> %d plane stages assigned\n", 115225fdd593SJeykumar Sankaran DPU_STAGE_MAX - DPU_STAGE_0); 115325fdd593SJeykumar Sankaran rc = -EINVAL; 115425fdd593SJeykumar Sankaran goto end; 115525fdd593SJeykumar Sankaran } else if (pstates[i].drm_pstate->crtc_x < mixer_width) { 115625fdd593SJeykumar Sankaran if (left_zpos_cnt == 2) { 115725fdd593SJeykumar Sankaran DPU_ERROR("> 2 planes @ stage %d on left\n", 115825fdd593SJeykumar Sankaran z_pos); 115925fdd593SJeykumar Sankaran rc = -EINVAL; 116025fdd593SJeykumar Sankaran goto end; 116125fdd593SJeykumar Sankaran } 116225fdd593SJeykumar Sankaran left_zpos_cnt++; 116325fdd593SJeykumar Sankaran 116425fdd593SJeykumar Sankaran } else { 116525fdd593SJeykumar Sankaran if (right_zpos_cnt == 2) { 116625fdd593SJeykumar Sankaran DPU_ERROR("> 2 planes @ stage %d on right\n", 116725fdd593SJeykumar Sankaran z_pos); 116825fdd593SJeykumar Sankaran rc = -EINVAL; 116925fdd593SJeykumar Sankaran goto end; 117025fdd593SJeykumar Sankaran } 117125fdd593SJeykumar Sankaran right_zpos_cnt++; 117225fdd593SJeykumar Sankaran } 117325fdd593SJeykumar Sankaran 117425fdd593SJeykumar Sankaran pstates[i].dpu_pstate->stage = z_pos + DPU_STAGE_0; 11755b702d78SStephen Boyd DRM_DEBUG_ATOMIC("%s: zpos %d\n", dpu_crtc->name, z_pos); 117625fdd593SJeykumar Sankaran } 117725fdd593SJeykumar Sankaran 117825fdd593SJeykumar Sankaran for (i = 0; i < multirect_count; i++) { 117925fdd593SJeykumar Sankaran if (dpu_plane_validate_multirect_v2(&multirect_plane[i])) { 118025fdd593SJeykumar Sankaran DPU_ERROR( 118125fdd593SJeykumar Sankaran "multirect validation failed for planes (%d - %d)\n", 118225fdd593SJeykumar Sankaran multirect_plane[i].r0->plane->base.id, 118325fdd593SJeykumar Sankaran multirect_plane[i].r1->plane->base.id); 118425fdd593SJeykumar Sankaran rc = -EINVAL; 118525fdd593SJeykumar Sankaran goto end; 118625fdd593SJeykumar Sankaran } 118725fdd593SJeykumar Sankaran } 118825fdd593SJeykumar Sankaran 1189241b507cSRob Clark atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); 1190241b507cSRob Clark 119129b77ad7SMaxime Ripard rc = dpu_core_perf_crtc_check(crtc, crtc_state); 119225fdd593SJeykumar Sankaran if (rc) { 119325fdd593SJeykumar Sankaran DPU_ERROR("crtc%d failed performance check %d\n", 119425fdd593SJeykumar Sankaran crtc->base.id, rc); 119525fdd593SJeykumar Sankaran goto end; 119625fdd593SJeykumar Sankaran } 119725fdd593SJeykumar Sankaran 119825fdd593SJeykumar Sankaran /* validate source split: 119925fdd593SJeykumar Sankaran * use pstates sorted by stage to check planes on same stage 120025fdd593SJeykumar Sankaran * we assume that all pipes are in source split so its valid to compare 120125fdd593SJeykumar Sankaran * without taking into account left/right mixer placement 120225fdd593SJeykumar Sankaran */ 120325fdd593SJeykumar Sankaran for (i = 1; i < cnt; i++) { 120425fdd593SJeykumar Sankaran struct plane_state *prv_pstate, *cur_pstate; 120525fdd593SJeykumar Sankaran struct drm_rect left_rect, right_rect; 120625fdd593SJeykumar Sankaran int32_t left_pid, right_pid; 120725fdd593SJeykumar Sankaran int32_t stage; 120825fdd593SJeykumar Sankaran 120925fdd593SJeykumar Sankaran prv_pstate = &pstates[i - 1]; 121025fdd593SJeykumar Sankaran cur_pstate = &pstates[i]; 121125fdd593SJeykumar Sankaran if (prv_pstate->stage != cur_pstate->stage) 121225fdd593SJeykumar Sankaran continue; 121325fdd593SJeykumar Sankaran 121425fdd593SJeykumar Sankaran stage = cur_pstate->stage; 121525fdd593SJeykumar Sankaran 121625fdd593SJeykumar Sankaran left_pid = prv_pstate->dpu_pstate->base.plane->base.id; 121725fdd593SJeykumar Sankaran left_rect = drm_plane_state_dest(prv_pstate->drm_pstate); 121825fdd593SJeykumar Sankaran 121925fdd593SJeykumar Sankaran right_pid = cur_pstate->dpu_pstate->base.plane->base.id; 122025fdd593SJeykumar Sankaran right_rect = drm_plane_state_dest(cur_pstate->drm_pstate); 122125fdd593SJeykumar Sankaran 122225fdd593SJeykumar Sankaran if (right_rect.x1 < left_rect.x1) { 122325fdd593SJeykumar Sankaran swap(left_pid, right_pid); 122425fdd593SJeykumar Sankaran swap(left_rect, right_rect); 122525fdd593SJeykumar Sankaran } 122625fdd593SJeykumar Sankaran 122725fdd593SJeykumar Sankaran /** 122825fdd593SJeykumar Sankaran * - planes are enumerated in pipe-priority order such that 122925fdd593SJeykumar Sankaran * planes with lower drm_id must be left-most in a shared 123025fdd593SJeykumar Sankaran * blend-stage when using source split. 123125fdd593SJeykumar Sankaran * - planes in source split must be contiguous in width 123225fdd593SJeykumar Sankaran * - planes in source split must have same dest yoff and height 123325fdd593SJeykumar Sankaran */ 123425fdd593SJeykumar Sankaran if (right_pid < left_pid) { 123525fdd593SJeykumar Sankaran DPU_ERROR( 123625fdd593SJeykumar Sankaran "invalid src split cfg. priority mismatch. stage: %d left: %d right: %d\n", 123725fdd593SJeykumar Sankaran stage, left_pid, right_pid); 123825fdd593SJeykumar Sankaran rc = -EINVAL; 123925fdd593SJeykumar Sankaran goto end; 124025fdd593SJeykumar Sankaran } else if (right_rect.x1 != drm_rect_width(&left_rect)) { 124125fdd593SJeykumar Sankaran DPU_ERROR("non-contiguous coordinates for src split. " 124225fdd593SJeykumar Sankaran "stage: %d left: " DRM_RECT_FMT " right: " 124325fdd593SJeykumar Sankaran DRM_RECT_FMT "\n", stage, 124425fdd593SJeykumar Sankaran DRM_RECT_ARG(&left_rect), 124525fdd593SJeykumar Sankaran DRM_RECT_ARG(&right_rect)); 124625fdd593SJeykumar Sankaran rc = -EINVAL; 124725fdd593SJeykumar Sankaran goto end; 124825fdd593SJeykumar Sankaran } else if (left_rect.y1 != right_rect.y1 || 124925fdd593SJeykumar Sankaran drm_rect_height(&left_rect) != drm_rect_height(&right_rect)) { 125025fdd593SJeykumar Sankaran DPU_ERROR("source split at stage: %d. invalid " 125125fdd593SJeykumar Sankaran "yoff/height: left: " DRM_RECT_FMT " right: " 125225fdd593SJeykumar Sankaran DRM_RECT_FMT "\n", stage, 125325fdd593SJeykumar Sankaran DRM_RECT_ARG(&left_rect), 125425fdd593SJeykumar Sankaran DRM_RECT_ARG(&right_rect)); 125525fdd593SJeykumar Sankaran rc = -EINVAL; 125625fdd593SJeykumar Sankaran goto end; 125725fdd593SJeykumar Sankaran } 125825fdd593SJeykumar Sankaran } 125925fdd593SJeykumar Sankaran 126025fdd593SJeykumar Sankaran end: 126125fdd593SJeykumar Sankaran kfree(pstates); 126225fdd593SJeykumar Sankaran return rc; 126325fdd593SJeykumar Sankaran } 126425fdd593SJeykumar Sankaran 126525fdd593SJeykumar Sankaran int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) 126625fdd593SJeykumar Sankaran { 12677a007a12SBruce Wang struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 1268a796ba2cSSean Paul struct drm_encoder *enc; 126925fdd593SJeykumar Sankaran 127025fdd593SJeykumar Sankaran trace_dpu_crtc_vblank(DRMID(&dpu_crtc->base), en, dpu_crtc); 1271a796ba2cSSean Paul 1272a796ba2cSSean Paul /* 1273a796ba2cSSean Paul * Normally we would iterate through encoder_mask in crtc state to find 1274a796ba2cSSean Paul * attached encoders. In this case, we might be disabling vblank _after_ 1275a796ba2cSSean Paul * encoder_mask has been cleared. 1276a796ba2cSSean Paul * 1277a796ba2cSSean Paul * Instead, we "assign" a crtc to the encoder in enable and clear it in 1278a796ba2cSSean Paul * disable (which is also after encoder_mask is cleared). So instead of 1279a796ba2cSSean Paul * using encoder mask, we'll ask the encoder to toggle itself iff it's 1280a796ba2cSSean Paul * currently assigned to our crtc. 1281a796ba2cSSean Paul * 1282a796ba2cSSean Paul * Note also that this function cannot be called while crtc is disabled 1283a796ba2cSSean Paul * since we use drm_crtc_vblank_on/off. So we don't need to worry 1284a796ba2cSSean Paul * about the assigned crtcs being inconsistent with the current state 1285a796ba2cSSean Paul * (which means no need to worry about modeset locks). 1286a796ba2cSSean Paul */ 1287a796ba2cSSean Paul list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { 1288a796ba2cSSean Paul trace_dpu_crtc_vblank_enable(DRMID(crtc), DRMID(enc), en, 1289a796ba2cSSean Paul dpu_crtc); 1290a796ba2cSSean Paul 1291a796ba2cSSean Paul dpu_encoder_toggle_vblank_for_crtc(enc, crtc, en); 129225fdd593SJeykumar Sankaran } 129325fdd593SJeykumar Sankaran 129425fdd593SJeykumar Sankaran return 0; 129525fdd593SJeykumar Sankaran } 129625fdd593SJeykumar Sankaran 129725fdd593SJeykumar Sankaran #ifdef CONFIG_DEBUG_FS 129825fdd593SJeykumar Sankaran static int _dpu_debugfs_status_show(struct seq_file *s, void *data) 129925fdd593SJeykumar Sankaran { 130025fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc; 130125fdd593SJeykumar Sankaran struct dpu_plane_state *pstate = NULL; 130225fdd593SJeykumar Sankaran struct dpu_crtc_mixer *m; 130325fdd593SJeykumar Sankaran 130425fdd593SJeykumar Sankaran struct drm_crtc *crtc; 130525fdd593SJeykumar Sankaran struct drm_plane *plane; 130625fdd593SJeykumar Sankaran struct drm_display_mode *mode; 130725fdd593SJeykumar Sankaran struct drm_framebuffer *fb; 130825fdd593SJeykumar Sankaran struct drm_plane_state *state; 130925fdd593SJeykumar Sankaran struct dpu_crtc_state *cstate; 131025fdd593SJeykumar Sankaran 131125fdd593SJeykumar Sankaran int i, out_width; 131225fdd593SJeykumar Sankaran 131325fdd593SJeykumar Sankaran dpu_crtc = s->private; 131425fdd593SJeykumar Sankaran crtc = &dpu_crtc->base; 13159222cdd2SJeykumar Sankaran 13169222cdd2SJeykumar Sankaran drm_modeset_lock_all(crtc->dev); 131725fdd593SJeykumar Sankaran cstate = to_dpu_crtc_state(crtc->state); 131825fdd593SJeykumar Sankaran 131925fdd593SJeykumar Sankaran mode = &crtc->state->adjusted_mode; 13203804a982SJordan Crouse out_width = mode->hdisplay / cstate->num_mixers; 132125fdd593SJeykumar Sankaran 132225fdd593SJeykumar Sankaran seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id, 132325fdd593SJeykumar Sankaran mode->hdisplay, mode->vdisplay); 132425fdd593SJeykumar Sankaran 132525fdd593SJeykumar Sankaran seq_puts(s, "\n"); 132625fdd593SJeykumar Sankaran 13279222cdd2SJeykumar Sankaran for (i = 0; i < cstate->num_mixers; ++i) { 13289222cdd2SJeykumar Sankaran m = &cstate->mixers[i]; 132925fdd593SJeykumar Sankaran seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", 1330cf6916f4SJeykumar Sankaran m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0, 133125fdd593SJeykumar Sankaran out_width, mode->vdisplay); 133225fdd593SJeykumar Sankaran } 133325fdd593SJeykumar Sankaran 133425fdd593SJeykumar Sankaran seq_puts(s, "\n"); 133525fdd593SJeykumar Sankaran 133625fdd593SJeykumar Sankaran drm_atomic_crtc_for_each_plane(plane, crtc) { 133725fdd593SJeykumar Sankaran pstate = to_dpu_plane_state(plane->state); 133825fdd593SJeykumar Sankaran state = plane->state; 133925fdd593SJeykumar Sankaran 134025fdd593SJeykumar Sankaran if (!pstate || !state) 134125fdd593SJeykumar Sankaran continue; 134225fdd593SJeykumar Sankaran 134325fdd593SJeykumar Sankaran seq_printf(s, "\tplane:%u stage:%d\n", plane->base.id, 134425fdd593SJeykumar Sankaran pstate->stage); 134525fdd593SJeykumar Sankaran 134625fdd593SJeykumar Sankaran if (plane->state->fb) { 134725fdd593SJeykumar Sankaran fb = plane->state->fb; 134825fdd593SJeykumar Sankaran 134925fdd593SJeykumar Sankaran seq_printf(s, "\tfb:%d image format:%4.4s wxh:%ux%u ", 135025fdd593SJeykumar Sankaran fb->base.id, (char *) &fb->format->format, 135125fdd593SJeykumar Sankaran fb->width, fb->height); 135225fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(fb->format->cpp); ++i) 135325fdd593SJeykumar Sankaran seq_printf(s, "cpp[%d]:%u ", 135425fdd593SJeykumar Sankaran i, fb->format->cpp[i]); 135525fdd593SJeykumar Sankaran seq_puts(s, "\n\t"); 135625fdd593SJeykumar Sankaran 135725fdd593SJeykumar Sankaran seq_printf(s, "modifier:%8llu ", fb->modifier); 135825fdd593SJeykumar Sankaran seq_puts(s, "\n"); 135925fdd593SJeykumar Sankaran 136025fdd593SJeykumar Sankaran seq_puts(s, "\t"); 136125fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) 136225fdd593SJeykumar Sankaran seq_printf(s, "pitches[%d]:%8u ", i, 136325fdd593SJeykumar Sankaran fb->pitches[i]); 136425fdd593SJeykumar Sankaran seq_puts(s, "\n"); 136525fdd593SJeykumar Sankaran 136625fdd593SJeykumar Sankaran seq_puts(s, "\t"); 136725fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) 136825fdd593SJeykumar Sankaran seq_printf(s, "offsets[%d]:%8u ", i, 136925fdd593SJeykumar Sankaran fb->offsets[i]); 137025fdd593SJeykumar Sankaran seq_puts(s, "\n"); 137125fdd593SJeykumar Sankaran } 137225fdd593SJeykumar Sankaran 137325fdd593SJeykumar Sankaran seq_printf(s, "\tsrc_x:%4d src_y:%4d src_w:%4d src_h:%4d\n", 137425fdd593SJeykumar Sankaran state->src_x, state->src_y, state->src_w, state->src_h); 137525fdd593SJeykumar Sankaran 137625fdd593SJeykumar Sankaran seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n", 137725fdd593SJeykumar Sankaran state->crtc_x, state->crtc_y, state->crtc_w, 137825fdd593SJeykumar Sankaran state->crtc_h); 137925fdd593SJeykumar Sankaran seq_printf(s, "\tmultirect: mode: %d index: %d\n", 138025fdd593SJeykumar Sankaran pstate->multirect_mode, pstate->multirect_index); 138125fdd593SJeykumar Sankaran 138225fdd593SJeykumar Sankaran seq_puts(s, "\n"); 138325fdd593SJeykumar Sankaran } 138425fdd593SJeykumar Sankaran if (dpu_crtc->vblank_cb_count) { 138525fdd593SJeykumar Sankaran ktime_t diff = ktime_sub(ktime_get(), dpu_crtc->vblank_cb_time); 138625fdd593SJeykumar Sankaran s64 diff_ms = ktime_to_ms(diff); 138725fdd593SJeykumar Sankaran s64 fps = diff_ms ? div_s64( 138825fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_count * 1000, diff_ms) : 0; 138925fdd593SJeykumar Sankaran 139025fdd593SJeykumar Sankaran seq_printf(s, 139125fdd593SJeykumar Sankaran "vblank fps:%lld count:%u total:%llums total_framecount:%llu\n", 139225fdd593SJeykumar Sankaran fps, dpu_crtc->vblank_cb_count, 139325fdd593SJeykumar Sankaran ktime_to_ms(diff), dpu_crtc->play_count); 139425fdd593SJeykumar Sankaran 139525fdd593SJeykumar Sankaran /* reset time & count for next measurement */ 139625fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_count = 0; 139725fdd593SJeykumar Sankaran dpu_crtc->vblank_cb_time = ktime_set(0, 0); 139825fdd593SJeykumar Sankaran } 139925fdd593SJeykumar Sankaran 14009222cdd2SJeykumar Sankaran drm_modeset_unlock_all(crtc->dev); 140125fdd593SJeykumar Sankaran 140225fdd593SJeykumar Sankaran return 0; 140325fdd593SJeykumar Sankaran } 140425fdd593SJeykumar Sankaran 1405341a361cSQinglang Miao DEFINE_SHOW_ATTRIBUTE(_dpu_debugfs_status); 140625fdd593SJeykumar Sankaran 140725fdd593SJeykumar Sankaran static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v) 140825fdd593SJeykumar Sankaran { 140925fdd593SJeykumar Sankaran struct drm_crtc *crtc = (struct drm_crtc *) s->private; 141025fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 141125fdd593SJeykumar Sankaran 141225fdd593SJeykumar Sankaran seq_printf(s, "client type: %d\n", dpu_crtc_get_client_type(crtc)); 141325fdd593SJeykumar Sankaran seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc)); 141425fdd593SJeykumar Sankaran seq_printf(s, "core_clk_rate: %llu\n", 141525fdd593SJeykumar Sankaran dpu_crtc->cur_perf.core_clk_rate); 1416cb88482eSJayant Shekhar seq_printf(s, "bw_ctl: %llu\n", dpu_crtc->cur_perf.bw_ctl); 1417cb88482eSJayant Shekhar seq_printf(s, "max_per_pipe_ib: %llu\n", 1418cb88482eSJayant Shekhar dpu_crtc->cur_perf.max_per_pipe_ib); 141925fdd593SJeykumar Sankaran 142025fdd593SJeykumar Sankaran return 0; 142125fdd593SJeykumar Sankaran } 1422341a361cSQinglang Miao DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state); 142325fdd593SJeykumar Sankaran 142425fdd593SJeykumar Sankaran static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) 142525fdd593SJeykumar Sankaran { 14263d688410SJordan Crouse struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); 1427*927e8bcaSDmitry Baryshkov struct dentry *debugfs_root; 142825fdd593SJeykumar Sankaran 1429*927e8bcaSDmitry Baryshkov debugfs_root = debugfs_create_dir(dpu_crtc->name, 143025fdd593SJeykumar Sankaran crtc->dev->primary->debugfs_root); 143125fdd593SJeykumar Sankaran 143225fdd593SJeykumar Sankaran debugfs_create_file("status", 0400, 1433*927e8bcaSDmitry Baryshkov debugfs_root, 1434341a361cSQinglang Miao dpu_crtc, &_dpu_debugfs_status_fops); 143525fdd593SJeykumar Sankaran debugfs_create_file("state", 0600, 1436*927e8bcaSDmitry Baryshkov debugfs_root, 143725fdd593SJeykumar Sankaran &dpu_crtc->base, 143825fdd593SJeykumar Sankaran &dpu_crtc_debugfs_state_fops); 143925fdd593SJeykumar Sankaran 144025fdd593SJeykumar Sankaran return 0; 144125fdd593SJeykumar Sankaran } 144225fdd593SJeykumar Sankaran #else 144325fdd593SJeykumar Sankaran static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) 144425fdd593SJeykumar Sankaran { 144525fdd593SJeykumar Sankaran return 0; 144625fdd593SJeykumar Sankaran } 144725fdd593SJeykumar Sankaran #endif /* CONFIG_DEBUG_FS */ 144825fdd593SJeykumar Sankaran 144925fdd593SJeykumar Sankaran static int dpu_crtc_late_register(struct drm_crtc *crtc) 145025fdd593SJeykumar Sankaran { 145125fdd593SJeykumar Sankaran return _dpu_crtc_init_debugfs(crtc); 145225fdd593SJeykumar Sankaran } 145325fdd593SJeykumar Sankaran 145425fdd593SJeykumar Sankaran static const struct drm_crtc_funcs dpu_crtc_funcs = { 145525fdd593SJeykumar Sankaran .set_config = drm_atomic_helper_set_config, 145625fdd593SJeykumar Sankaran .destroy = dpu_crtc_destroy, 145725fdd593SJeykumar Sankaran .page_flip = drm_atomic_helper_page_flip, 145825fdd593SJeykumar Sankaran .reset = dpu_crtc_reset, 145925fdd593SJeykumar Sankaran .atomic_duplicate_state = dpu_crtc_duplicate_state, 146025fdd593SJeykumar Sankaran .atomic_destroy_state = dpu_crtc_destroy_state, 146125fdd593SJeykumar Sankaran .late_register = dpu_crtc_late_register, 146278d9b458SJessica Zhang .verify_crc_source = dpu_crtc_verify_crc_source, 146378d9b458SJessica Zhang .set_crc_source = dpu_crtc_set_crc_source, 146476e8cfd8SThomas Zimmermann .enable_vblank = msm_crtc_enable_vblank, 146576e8cfd8SThomas Zimmermann .disable_vblank = msm_crtc_disable_vblank, 146673743e72SKalyan Thota .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, 146773743e72SKalyan Thota .get_vblank_counter = dpu_crtc_get_vblank_counter, 146825fdd593SJeykumar Sankaran }; 146925fdd593SJeykumar Sankaran 147025fdd593SJeykumar Sankaran static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { 1471f7aafc8dSSean Paul .atomic_disable = dpu_crtc_disable, 147225fdd593SJeykumar Sankaran .atomic_enable = dpu_crtc_enable, 147325fdd593SJeykumar Sankaran .atomic_check = dpu_crtc_atomic_check, 147425fdd593SJeykumar Sankaran .atomic_begin = dpu_crtc_atomic_begin, 147525fdd593SJeykumar Sankaran .atomic_flush = dpu_crtc_atomic_flush, 147673743e72SKalyan Thota .get_scanout_position = dpu_crtc_get_scanout_position, 147725fdd593SJeykumar Sankaran }; 147825fdd593SJeykumar Sankaran 147925fdd593SJeykumar Sankaran /* initialize crtc */ 148007ca1fc0SSravanthi Kollukuduru struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, 148107ca1fc0SSravanthi Kollukuduru struct drm_plane *cursor) 148225fdd593SJeykumar Sankaran { 148325fdd593SJeykumar Sankaran struct drm_crtc *crtc = NULL; 148425fdd593SJeykumar Sankaran struct dpu_crtc *dpu_crtc = NULL; 1485c17aeda0SJordan Crouse int i; 148625fdd593SJeykumar Sankaran 148725fdd593SJeykumar Sankaran dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); 148825fdd593SJeykumar Sankaran if (!dpu_crtc) 148925fdd593SJeykumar Sankaran return ERR_PTR(-ENOMEM); 149025fdd593SJeykumar Sankaran 149125fdd593SJeykumar Sankaran crtc = &dpu_crtc->base; 149225fdd593SJeykumar Sankaran crtc->dev = dev; 149325fdd593SJeykumar Sankaran 149425fdd593SJeykumar Sankaran spin_lock_init(&dpu_crtc->spin_lock); 149525fdd593SJeykumar Sankaran atomic_set(&dpu_crtc->frame_pending, 0); 149625fdd593SJeykumar Sankaran 149725fdd593SJeykumar Sankaran init_completion(&dpu_crtc->frame_done_comp); 149825fdd593SJeykumar Sankaran 149925fdd593SJeykumar Sankaran INIT_LIST_HEAD(&dpu_crtc->frame_event_list); 150025fdd593SJeykumar Sankaran 150125fdd593SJeykumar Sankaran for (i = 0; i < ARRAY_SIZE(dpu_crtc->frame_events); i++) { 150225fdd593SJeykumar Sankaran INIT_LIST_HEAD(&dpu_crtc->frame_events[i].list); 150325fdd593SJeykumar Sankaran list_add(&dpu_crtc->frame_events[i].list, 150425fdd593SJeykumar Sankaran &dpu_crtc->frame_event_list); 150525fdd593SJeykumar Sankaran kthread_init_work(&dpu_crtc->frame_events[i].work, 150625fdd593SJeykumar Sankaran dpu_crtc_frame_event_work); 150725fdd593SJeykumar Sankaran } 150825fdd593SJeykumar Sankaran 150907ca1fc0SSravanthi Kollukuduru drm_crtc_init_with_planes(dev, crtc, plane, cursor, &dpu_crtc_funcs, 151025fdd593SJeykumar Sankaran NULL); 151125fdd593SJeykumar Sankaran 151225fdd593SJeykumar Sankaran drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); 151325fdd593SJeykumar Sankaran 15144259ff7aSKalyan Thota drm_crtc_enable_color_mgmt(crtc, 0, true, 0); 15154259ff7aSKalyan Thota 151625fdd593SJeykumar Sankaran /* save user friendly CRTC name for later */ 151725fdd593SJeykumar Sankaran snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); 151825fdd593SJeykumar Sankaran 151925fdd593SJeykumar Sankaran /* initialize event handling */ 1520c17aeda0SJordan Crouse spin_lock_init(&dpu_crtc->event_lock); 152125fdd593SJeykumar Sankaran 15225b702d78SStephen Boyd DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name); 152325fdd593SJeykumar Sankaran return crtc; 152425fdd593SJeykumar Sankaran } 1525