1*711a3b87SLiu Ying // SPDX-License-Identifier: GPL-2.0+ 2*711a3b87SLiu Ying /* 3*711a3b87SLiu Ying * Copyright 2024 NXP 4*711a3b87SLiu Ying */ 5*711a3b87SLiu Ying 6*711a3b87SLiu Ying #include <linux/completion.h> 7*711a3b87SLiu Ying #include <linux/container_of.h> 8*711a3b87SLiu Ying #include <linux/interrupt.h> 9*711a3b87SLiu Ying #include <linux/irqreturn.h> 10*711a3b87SLiu Ying #include <linux/pm_runtime.h> 11*711a3b87SLiu Ying #include <linux/spinlock.h> 12*711a3b87SLiu Ying 13*711a3b87SLiu Ying #include <drm/drm_atomic.h> 14*711a3b87SLiu Ying #include <drm/drm_atomic_helper.h> 15*711a3b87SLiu Ying #include <drm/drm_atomic_state_helper.h> 16*711a3b87SLiu Ying #include <drm/drm_crtc.h> 17*711a3b87SLiu Ying #include <drm/drm_device.h> 18*711a3b87SLiu Ying #include <drm/drm_drv.h> 19*711a3b87SLiu Ying #include <drm/drm_modes.h> 20*711a3b87SLiu Ying #include <drm/drm_modeset_helper_vtables.h> 21*711a3b87SLiu Ying #include <drm/drm_plane.h> 22*711a3b87SLiu Ying #include <drm/drm_print.h> 23*711a3b87SLiu Ying #include <drm/drm_vblank.h> 24*711a3b87SLiu Ying 25*711a3b87SLiu Ying #include "dc-de.h" 26*711a3b87SLiu Ying #include "dc-drv.h" 27*711a3b87SLiu Ying #include "dc-kms.h" 28*711a3b87SLiu Ying #include "dc-pe.h" 29*711a3b87SLiu Ying 30*711a3b87SLiu Ying #define dc_crtc_dbg(crtc, fmt, ...) \ 31*711a3b87SLiu Ying do { \ 32*711a3b87SLiu Ying struct drm_crtc *_crtc = (crtc); \ 33*711a3b87SLiu Ying drm_dbg_kms(_crtc->dev, "[CRTC:%d:%s] " fmt, \ 34*711a3b87SLiu Ying _crtc->base.id, _crtc->name, ##__VA_ARGS__); \ 35*711a3b87SLiu Ying } while (0) 36*711a3b87SLiu Ying 37*711a3b87SLiu Ying #define dc_crtc_err(crtc, fmt, ...) \ 38*711a3b87SLiu Ying do { \ 39*711a3b87SLiu Ying struct drm_crtc *_crtc = (crtc); \ 40*711a3b87SLiu Ying drm_err(_crtc->dev, "[CRTC:%d:%s] " fmt, \ 41*711a3b87SLiu Ying _crtc->base.id, _crtc->name, ##__VA_ARGS__); \ 42*711a3b87SLiu Ying } while (0) 43*711a3b87SLiu Ying 44*711a3b87SLiu Ying #define DC_CRTC_WAIT_FOR_COMPLETION_TIMEOUT(c) \ 45*711a3b87SLiu Ying do { \ 46*711a3b87SLiu Ying unsigned long ret; \ 47*711a3b87SLiu Ying ret = wait_for_completion_timeout(&dc_crtc->c, HZ); \ 48*711a3b87SLiu Ying if (ret == 0) \ 49*711a3b87SLiu Ying dc_crtc_err(crtc, "%s: wait for " #c " timeout\n", \ 50*711a3b87SLiu Ying __func__); \ 51*711a3b87SLiu Ying } while (0) 52*711a3b87SLiu Ying 53*711a3b87SLiu Ying #define DC_CRTC_CHECK_FRAMEGEN_FIFO(fg) \ 54*711a3b87SLiu Ying do { \ 55*711a3b87SLiu Ying struct dc_fg *_fg = (fg); \ 56*711a3b87SLiu Ying if (dc_fg_secondary_requests_to_read_empty_fifo(_fg)) { \ 57*711a3b87SLiu Ying dc_fg_secondary_clear_channel_status(_fg); \ 58*711a3b87SLiu Ying dc_crtc_err(crtc, "%s: FrameGen FIFO empty\n", \ 59*711a3b87SLiu Ying __func__); \ 60*711a3b87SLiu Ying } \ 61*711a3b87SLiu Ying } while (0) 62*711a3b87SLiu Ying 63*711a3b87SLiu Ying #define DC_CRTC_WAIT_FOR_FRAMEGEN_SECONDARY_SYNCUP(fg) \ 64*711a3b87SLiu Ying do { \ 65*711a3b87SLiu Ying if (dc_fg_wait_for_secondary_syncup(fg)) \ 66*711a3b87SLiu Ying dc_crtc_err(crtc, \ 67*711a3b87SLiu Ying "%s: FrameGen secondary channel isn't syncup\n",\ 68*711a3b87SLiu Ying __func__); \ 69*711a3b87SLiu Ying } while (0) 70*711a3b87SLiu Ying 71*711a3b87SLiu Ying static inline struct dc_crtc *to_dc_crtc(struct drm_crtc *crtc) 72*711a3b87SLiu Ying { 73*711a3b87SLiu Ying return container_of(crtc, struct dc_crtc, base); 74*711a3b87SLiu Ying } 75*711a3b87SLiu Ying 76*711a3b87SLiu Ying static u32 dc_crtc_get_vblank_counter(struct drm_crtc *crtc) 77*711a3b87SLiu Ying { 78*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 79*711a3b87SLiu Ying 80*711a3b87SLiu Ying return dc_fg_get_frame_index(dc_crtc->fg); 81*711a3b87SLiu Ying } 82*711a3b87SLiu Ying 83*711a3b87SLiu Ying static int dc_crtc_enable_vblank(struct drm_crtc *crtc) 84*711a3b87SLiu Ying { 85*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 86*711a3b87SLiu Ying 87*711a3b87SLiu Ying enable_irq(dc_crtc->irq_dec_framecomplete); 88*711a3b87SLiu Ying 89*711a3b87SLiu Ying return 0; 90*711a3b87SLiu Ying } 91*711a3b87SLiu Ying 92*711a3b87SLiu Ying static void dc_crtc_disable_vblank(struct drm_crtc *crtc) 93*711a3b87SLiu Ying { 94*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 95*711a3b87SLiu Ying 96*711a3b87SLiu Ying /* nosync due to atomic context */ 97*711a3b87SLiu Ying disable_irq_nosync(dc_crtc->irq_dec_framecomplete); 98*711a3b87SLiu Ying } 99*711a3b87SLiu Ying 100*711a3b87SLiu Ying static const struct drm_crtc_funcs dc_crtc_funcs = { 101*711a3b87SLiu Ying .reset = drm_atomic_helper_crtc_reset, 102*711a3b87SLiu Ying .destroy = drm_crtc_cleanup, 103*711a3b87SLiu Ying .set_config = drm_atomic_helper_set_config, 104*711a3b87SLiu Ying .page_flip = drm_atomic_helper_page_flip, 105*711a3b87SLiu Ying .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 106*711a3b87SLiu Ying .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 107*711a3b87SLiu Ying .get_vblank_counter = dc_crtc_get_vblank_counter, 108*711a3b87SLiu Ying .enable_vblank = dc_crtc_enable_vblank, 109*711a3b87SLiu Ying .disable_vblank = dc_crtc_disable_vblank, 110*711a3b87SLiu Ying .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, 111*711a3b87SLiu Ying }; 112*711a3b87SLiu Ying 113*711a3b87SLiu Ying static void dc_crtc_queue_state_event(struct drm_crtc_state *crtc_state) 114*711a3b87SLiu Ying { 115*711a3b87SLiu Ying struct drm_crtc *crtc = crtc_state->crtc; 116*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 117*711a3b87SLiu Ying 118*711a3b87SLiu Ying spin_lock_irq(&crtc->dev->event_lock); 119*711a3b87SLiu Ying if (crtc_state->event) { 120*711a3b87SLiu Ying WARN_ON(drm_crtc_vblank_get(crtc)); 121*711a3b87SLiu Ying WARN_ON(dc_crtc->event); 122*711a3b87SLiu Ying dc_crtc->event = crtc_state->event; 123*711a3b87SLiu Ying crtc_state->event = NULL; 124*711a3b87SLiu Ying } 125*711a3b87SLiu Ying spin_unlock_irq(&crtc->dev->event_lock); 126*711a3b87SLiu Ying } 127*711a3b87SLiu Ying 128*711a3b87SLiu Ying static inline enum drm_mode_status 129*711a3b87SLiu Ying dc_crtc_check_clock(struct dc_crtc *dc_crtc, int clk_khz) 130*711a3b87SLiu Ying { 131*711a3b87SLiu Ying return dc_fg_check_clock(dc_crtc->fg, clk_khz); 132*711a3b87SLiu Ying } 133*711a3b87SLiu Ying 134*711a3b87SLiu Ying static enum drm_mode_status 135*711a3b87SLiu Ying dc_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) 136*711a3b87SLiu Ying { 137*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 138*711a3b87SLiu Ying enum drm_mode_status status; 139*711a3b87SLiu Ying 140*711a3b87SLiu Ying status = dc_crtc_check_clock(dc_crtc, mode->clock); 141*711a3b87SLiu Ying if (status != MODE_OK) 142*711a3b87SLiu Ying return status; 143*711a3b87SLiu Ying 144*711a3b87SLiu Ying if (mode->crtc_clock > DC_FRAMEGEN_MAX_CLOCK_KHZ) 145*711a3b87SLiu Ying return MODE_CLOCK_HIGH; 146*711a3b87SLiu Ying 147*711a3b87SLiu Ying return MODE_OK; 148*711a3b87SLiu Ying } 149*711a3b87SLiu Ying 150*711a3b87SLiu Ying static int 151*711a3b87SLiu Ying dc_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) 152*711a3b87SLiu Ying { 153*711a3b87SLiu Ying struct drm_crtc_state *new_crtc_state = 154*711a3b87SLiu Ying drm_atomic_get_new_crtc_state(state, crtc); 155*711a3b87SLiu Ying struct drm_display_mode *adj = &new_crtc_state->adjusted_mode; 156*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 157*711a3b87SLiu Ying enum drm_mode_status status; 158*711a3b87SLiu Ying 159*711a3b87SLiu Ying status = dc_crtc_check_clock(dc_crtc, adj->clock); 160*711a3b87SLiu Ying if (status != MODE_OK) 161*711a3b87SLiu Ying return -EINVAL; 162*711a3b87SLiu Ying 163*711a3b87SLiu Ying return 0; 164*711a3b87SLiu Ying } 165*711a3b87SLiu Ying 166*711a3b87SLiu Ying static void 167*711a3b87SLiu Ying dc_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state) 168*711a3b87SLiu Ying { 169*711a3b87SLiu Ying struct drm_crtc_state *new_crtc_state = 170*711a3b87SLiu Ying drm_atomic_get_new_crtc_state(state, crtc); 171*711a3b87SLiu Ying struct dc_drm_device *dc_drm = to_dc_drm_device(crtc->dev); 172*711a3b87SLiu Ying int idx, ret; 173*711a3b87SLiu Ying 174*711a3b87SLiu Ying if (!drm_atomic_crtc_needs_modeset(new_crtc_state) || 175*711a3b87SLiu Ying !new_crtc_state->active) 176*711a3b87SLiu Ying return; 177*711a3b87SLiu Ying 178*711a3b87SLiu Ying if (!drm_dev_enter(crtc->dev, &idx)) 179*711a3b87SLiu Ying return; 180*711a3b87SLiu Ying 181*711a3b87SLiu Ying /* request pixel engine power-on when CRTC starts to be active */ 182*711a3b87SLiu Ying ret = pm_runtime_resume_and_get(dc_drm->pe->dev); 183*711a3b87SLiu Ying if (ret) 184*711a3b87SLiu Ying dc_crtc_err(crtc, "failed to get DC pixel engine RPM: %d\n", 185*711a3b87SLiu Ying ret); 186*711a3b87SLiu Ying 187*711a3b87SLiu Ying drm_dev_exit(idx); 188*711a3b87SLiu Ying } 189*711a3b87SLiu Ying 190*711a3b87SLiu Ying static void 191*711a3b87SLiu Ying dc_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) 192*711a3b87SLiu Ying { 193*711a3b87SLiu Ying struct drm_crtc_state *old_crtc_state = 194*711a3b87SLiu Ying drm_atomic_get_old_crtc_state(state, crtc); 195*711a3b87SLiu Ying struct drm_crtc_state *new_crtc_state = 196*711a3b87SLiu Ying drm_atomic_get_new_crtc_state(state, crtc); 197*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 198*711a3b87SLiu Ying int idx; 199*711a3b87SLiu Ying 200*711a3b87SLiu Ying if (drm_atomic_crtc_needs_modeset(new_crtc_state) || 201*711a3b87SLiu Ying (!old_crtc_state->active && !new_crtc_state->active)) 202*711a3b87SLiu Ying return; 203*711a3b87SLiu Ying 204*711a3b87SLiu Ying if (!drm_dev_enter(crtc->dev, &idx)) 205*711a3b87SLiu Ying goto out; 206*711a3b87SLiu Ying 207*711a3b87SLiu Ying enable_irq(dc_crtc->irq_ed_cont_shdload); 208*711a3b87SLiu Ying 209*711a3b87SLiu Ying /* flush plane update out to display */ 210*711a3b87SLiu Ying dc_ed_pec_sync_trigger(dc_crtc->ed_cont); 211*711a3b87SLiu Ying 212*711a3b87SLiu Ying DC_CRTC_WAIT_FOR_COMPLETION_TIMEOUT(ed_cont_shdload_done); 213*711a3b87SLiu Ying 214*711a3b87SLiu Ying disable_irq(dc_crtc->irq_ed_cont_shdload); 215*711a3b87SLiu Ying 216*711a3b87SLiu Ying DC_CRTC_CHECK_FRAMEGEN_FIFO(dc_crtc->fg); 217*711a3b87SLiu Ying 218*711a3b87SLiu Ying drm_dev_exit(idx); 219*711a3b87SLiu Ying 220*711a3b87SLiu Ying out: 221*711a3b87SLiu Ying dc_crtc_queue_state_event(new_crtc_state); 222*711a3b87SLiu Ying } 223*711a3b87SLiu Ying 224*711a3b87SLiu Ying static void 225*711a3b87SLiu Ying dc_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) 226*711a3b87SLiu Ying { 227*711a3b87SLiu Ying struct drm_crtc_state *new_crtc_state = 228*711a3b87SLiu Ying drm_atomic_get_new_crtc_state(state, crtc); 229*711a3b87SLiu Ying struct drm_display_mode *adj = &new_crtc_state->adjusted_mode; 230*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 231*711a3b87SLiu Ying enum dc_link_id cf_link; 232*711a3b87SLiu Ying int idx, ret; 233*711a3b87SLiu Ying 234*711a3b87SLiu Ying dc_crtc_dbg(crtc, "mode " DRM_MODE_FMT "\n", DRM_MODE_ARG(adj)); 235*711a3b87SLiu Ying 236*711a3b87SLiu Ying drm_crtc_vblank_on(crtc); 237*711a3b87SLiu Ying 238*711a3b87SLiu Ying if (!drm_dev_enter(crtc->dev, &idx)) 239*711a3b87SLiu Ying goto out; 240*711a3b87SLiu Ying 241*711a3b87SLiu Ying /* request display engine power-on when CRTC is enabled */ 242*711a3b87SLiu Ying ret = pm_runtime_resume_and_get(dc_crtc->de->dev); 243*711a3b87SLiu Ying if (ret < 0) 244*711a3b87SLiu Ying dc_crtc_err(crtc, "failed to get DC display engine RPM: %d\n", 245*711a3b87SLiu Ying ret); 246*711a3b87SLiu Ying 247*711a3b87SLiu Ying enable_irq(dc_crtc->irq_dec_shdload); 248*711a3b87SLiu Ying enable_irq(dc_crtc->irq_ed_cont_shdload); 249*711a3b87SLiu Ying enable_irq(dc_crtc->irq_ed_safe_shdload); 250*711a3b87SLiu Ying 251*711a3b87SLiu Ying dc_fg_cfg_videomode(dc_crtc->fg, adj); 252*711a3b87SLiu Ying 253*711a3b87SLiu Ying dc_cf_framedimensions(dc_crtc->cf_cont, 254*711a3b87SLiu Ying adj->crtc_hdisplay, adj->crtc_vdisplay); 255*711a3b87SLiu Ying dc_cf_framedimensions(dc_crtc->cf_safe, 256*711a3b87SLiu Ying adj->crtc_hdisplay, adj->crtc_vdisplay); 257*711a3b87SLiu Ying 258*711a3b87SLiu Ying /* constframe in safety stream shows blue frame */ 259*711a3b87SLiu Ying dc_cf_constantcolor_blue(dc_crtc->cf_safe); 260*711a3b87SLiu Ying cf_link = dc_cf_get_link_id(dc_crtc->cf_safe); 261*711a3b87SLiu Ying dc_ed_pec_src_sel(dc_crtc->ed_safe, cf_link); 262*711a3b87SLiu Ying 263*711a3b87SLiu Ying /* show CRTC background if no plane is enabled */ 264*711a3b87SLiu Ying if (new_crtc_state->plane_mask == 0) { 265*711a3b87SLiu Ying /* constframe in content stream shows black frame */ 266*711a3b87SLiu Ying dc_cf_constantcolor_black(dc_crtc->cf_cont); 267*711a3b87SLiu Ying 268*711a3b87SLiu Ying cf_link = dc_cf_get_link_id(dc_crtc->cf_cont); 269*711a3b87SLiu Ying dc_ed_pec_src_sel(dc_crtc->ed_cont, cf_link); 270*711a3b87SLiu Ying } 271*711a3b87SLiu Ying 272*711a3b87SLiu Ying dc_fg_enable_clock(dc_crtc->fg); 273*711a3b87SLiu Ying dc_ed_pec_sync_trigger(dc_crtc->ed_cont); 274*711a3b87SLiu Ying dc_ed_pec_sync_trigger(dc_crtc->ed_safe); 275*711a3b87SLiu Ying dc_fg_shdtokgen(dc_crtc->fg); 276*711a3b87SLiu Ying dc_fg_enable(dc_crtc->fg); 277*711a3b87SLiu Ying 278*711a3b87SLiu Ying DC_CRTC_WAIT_FOR_COMPLETION_TIMEOUT(ed_safe_shdload_done); 279*711a3b87SLiu Ying DC_CRTC_WAIT_FOR_COMPLETION_TIMEOUT(ed_cont_shdload_done); 280*711a3b87SLiu Ying DC_CRTC_WAIT_FOR_COMPLETION_TIMEOUT(dec_shdload_done); 281*711a3b87SLiu Ying 282*711a3b87SLiu Ying disable_irq(dc_crtc->irq_ed_safe_shdload); 283*711a3b87SLiu Ying disable_irq(dc_crtc->irq_ed_cont_shdload); 284*711a3b87SLiu Ying disable_irq(dc_crtc->irq_dec_shdload); 285*711a3b87SLiu Ying 286*711a3b87SLiu Ying DC_CRTC_WAIT_FOR_FRAMEGEN_SECONDARY_SYNCUP(dc_crtc->fg); 287*711a3b87SLiu Ying 288*711a3b87SLiu Ying DC_CRTC_CHECK_FRAMEGEN_FIFO(dc_crtc->fg); 289*711a3b87SLiu Ying 290*711a3b87SLiu Ying drm_dev_exit(idx); 291*711a3b87SLiu Ying 292*711a3b87SLiu Ying out: 293*711a3b87SLiu Ying dc_crtc_queue_state_event(new_crtc_state); 294*711a3b87SLiu Ying } 295*711a3b87SLiu Ying 296*711a3b87SLiu Ying static void 297*711a3b87SLiu Ying dc_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) 298*711a3b87SLiu Ying { 299*711a3b87SLiu Ying struct drm_crtc_state *new_crtc_state = 300*711a3b87SLiu Ying drm_atomic_get_new_crtc_state(state, crtc); 301*711a3b87SLiu Ying struct dc_drm_device *dc_drm = to_dc_drm_device(crtc->dev); 302*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 303*711a3b87SLiu Ying int idx, ret; 304*711a3b87SLiu Ying 305*711a3b87SLiu Ying if (!drm_dev_enter(crtc->dev, &idx)) 306*711a3b87SLiu Ying goto out; 307*711a3b87SLiu Ying 308*711a3b87SLiu Ying enable_irq(dc_crtc->irq_dec_seqcomplete); 309*711a3b87SLiu Ying dc_fg_disable(dc_crtc->fg); 310*711a3b87SLiu Ying DC_CRTC_WAIT_FOR_COMPLETION_TIMEOUT(dec_seqcomplete_done); 311*711a3b87SLiu Ying disable_irq(dc_crtc->irq_dec_seqcomplete); 312*711a3b87SLiu Ying 313*711a3b87SLiu Ying dc_fg_disable_clock(dc_crtc->fg); 314*711a3b87SLiu Ying 315*711a3b87SLiu Ying /* request pixel engine power-off as plane is off too */ 316*711a3b87SLiu Ying ret = pm_runtime_put(dc_drm->pe->dev); 317*711a3b87SLiu Ying if (ret) 318*711a3b87SLiu Ying dc_crtc_err(crtc, "failed to put DC pixel engine RPM: %d\n", 319*711a3b87SLiu Ying ret); 320*711a3b87SLiu Ying 321*711a3b87SLiu Ying /* request display engine power-off when CRTC is disabled */ 322*711a3b87SLiu Ying ret = pm_runtime_put(dc_crtc->de->dev); 323*711a3b87SLiu Ying if (ret < 0) 324*711a3b87SLiu Ying dc_crtc_err(crtc, "failed to put DC display engine RPM: %d\n", 325*711a3b87SLiu Ying ret); 326*711a3b87SLiu Ying 327*711a3b87SLiu Ying drm_dev_exit(idx); 328*711a3b87SLiu Ying 329*711a3b87SLiu Ying out: 330*711a3b87SLiu Ying drm_crtc_vblank_off(crtc); 331*711a3b87SLiu Ying 332*711a3b87SLiu Ying spin_lock_irq(&crtc->dev->event_lock); 333*711a3b87SLiu Ying if (new_crtc_state->event && !new_crtc_state->active) { 334*711a3b87SLiu Ying drm_crtc_send_vblank_event(crtc, new_crtc_state->event); 335*711a3b87SLiu Ying new_crtc_state->event = NULL; 336*711a3b87SLiu Ying } 337*711a3b87SLiu Ying spin_unlock_irq(&crtc->dev->event_lock); 338*711a3b87SLiu Ying } 339*711a3b87SLiu Ying 340*711a3b87SLiu Ying static bool dc_crtc_get_scanout_position(struct drm_crtc *crtc, 341*711a3b87SLiu Ying bool in_vblank_irq, 342*711a3b87SLiu Ying int *vpos, int *hpos, 343*711a3b87SLiu Ying ktime_t *stime, ktime_t *etime, 344*711a3b87SLiu Ying const struct drm_display_mode *mode) 345*711a3b87SLiu Ying { 346*711a3b87SLiu Ying struct dc_crtc *dc_crtc = to_dc_crtc(crtc); 347*711a3b87SLiu Ying int vdisplay = mode->crtc_vdisplay; 348*711a3b87SLiu Ying int vtotal = mode->crtc_vtotal; 349*711a3b87SLiu Ying bool reliable; 350*711a3b87SLiu Ying int line; 351*711a3b87SLiu Ying int idx; 352*711a3b87SLiu Ying 353*711a3b87SLiu Ying if (stime) 354*711a3b87SLiu Ying *stime = ktime_get(); 355*711a3b87SLiu Ying 356*711a3b87SLiu Ying if (!drm_dev_enter(crtc->dev, &idx)) { 357*711a3b87SLiu Ying reliable = false; 358*711a3b87SLiu Ying *vpos = 0; 359*711a3b87SLiu Ying *hpos = 0; 360*711a3b87SLiu Ying goto out; 361*711a3b87SLiu Ying } 362*711a3b87SLiu Ying 363*711a3b87SLiu Ying /* line index starts with 0 for the first active output line */ 364*711a3b87SLiu Ying line = dc_fg_get_line_index(dc_crtc->fg); 365*711a3b87SLiu Ying 366*711a3b87SLiu Ying if (line < vdisplay) 367*711a3b87SLiu Ying /* active scanout area - positive */ 368*711a3b87SLiu Ying *vpos = line + 1; 369*711a3b87SLiu Ying else 370*711a3b87SLiu Ying /* inside vblank - negative */ 371*711a3b87SLiu Ying *vpos = line - (vtotal - 1); 372*711a3b87SLiu Ying 373*711a3b87SLiu Ying *hpos = 0; 374*711a3b87SLiu Ying 375*711a3b87SLiu Ying reliable = true; 376*711a3b87SLiu Ying 377*711a3b87SLiu Ying drm_dev_exit(idx); 378*711a3b87SLiu Ying out: 379*711a3b87SLiu Ying if (etime) 380*711a3b87SLiu Ying *etime = ktime_get(); 381*711a3b87SLiu Ying 382*711a3b87SLiu Ying return reliable; 383*711a3b87SLiu Ying } 384*711a3b87SLiu Ying 385*711a3b87SLiu Ying static const struct drm_crtc_helper_funcs dc_helper_funcs = { 386*711a3b87SLiu Ying .mode_valid = dc_crtc_mode_valid, 387*711a3b87SLiu Ying .atomic_check = dc_crtc_atomic_check, 388*711a3b87SLiu Ying .atomic_begin = dc_crtc_atomic_begin, 389*711a3b87SLiu Ying .atomic_flush = dc_crtc_atomic_flush, 390*711a3b87SLiu Ying .atomic_enable = dc_crtc_atomic_enable, 391*711a3b87SLiu Ying .atomic_disable = dc_crtc_atomic_disable, 392*711a3b87SLiu Ying .get_scanout_position = dc_crtc_get_scanout_position, 393*711a3b87SLiu Ying }; 394*711a3b87SLiu Ying 395*711a3b87SLiu Ying static irqreturn_t dc_crtc_irq_handler_dec_framecomplete(int irq, void *dev_id) 396*711a3b87SLiu Ying { 397*711a3b87SLiu Ying struct dc_crtc *dc_crtc = dev_id; 398*711a3b87SLiu Ying struct drm_crtc *crtc = &dc_crtc->base; 399*711a3b87SLiu Ying unsigned long flags; 400*711a3b87SLiu Ying 401*711a3b87SLiu Ying drm_crtc_handle_vblank(crtc); 402*711a3b87SLiu Ying 403*711a3b87SLiu Ying spin_lock_irqsave(&crtc->dev->event_lock, flags); 404*711a3b87SLiu Ying if (dc_crtc->event) { 405*711a3b87SLiu Ying drm_crtc_send_vblank_event(crtc, dc_crtc->event); 406*711a3b87SLiu Ying dc_crtc->event = NULL; 407*711a3b87SLiu Ying drm_crtc_vblank_put(crtc); 408*711a3b87SLiu Ying } 409*711a3b87SLiu Ying spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 410*711a3b87SLiu Ying 411*711a3b87SLiu Ying return IRQ_HANDLED; 412*711a3b87SLiu Ying } 413*711a3b87SLiu Ying 414*711a3b87SLiu Ying static irqreturn_t 415*711a3b87SLiu Ying dc_crtc_irq_handler_dec_seqcomplete_done(int irq, void *dev_id) 416*711a3b87SLiu Ying { 417*711a3b87SLiu Ying struct dc_crtc *dc_crtc = dev_id; 418*711a3b87SLiu Ying 419*711a3b87SLiu Ying complete(&dc_crtc->dec_seqcomplete_done); 420*711a3b87SLiu Ying 421*711a3b87SLiu Ying return IRQ_HANDLED; 422*711a3b87SLiu Ying } 423*711a3b87SLiu Ying 424*711a3b87SLiu Ying static irqreturn_t dc_crtc_irq_handler_dec_shdload_done(int irq, void *dev_id) 425*711a3b87SLiu Ying { 426*711a3b87SLiu Ying struct dc_crtc *dc_crtc = dev_id; 427*711a3b87SLiu Ying 428*711a3b87SLiu Ying complete(&dc_crtc->dec_shdload_done); 429*711a3b87SLiu Ying 430*711a3b87SLiu Ying return IRQ_HANDLED; 431*711a3b87SLiu Ying } 432*711a3b87SLiu Ying 433*711a3b87SLiu Ying static irqreturn_t 434*711a3b87SLiu Ying dc_crtc_irq_handler_ed_cont_shdload_done(int irq, void *dev_id) 435*711a3b87SLiu Ying { 436*711a3b87SLiu Ying struct dc_crtc *dc_crtc = dev_id; 437*711a3b87SLiu Ying 438*711a3b87SLiu Ying complete(&dc_crtc->ed_cont_shdload_done); 439*711a3b87SLiu Ying 440*711a3b87SLiu Ying return IRQ_HANDLED; 441*711a3b87SLiu Ying } 442*711a3b87SLiu Ying 443*711a3b87SLiu Ying static irqreturn_t 444*711a3b87SLiu Ying dc_crtc_irq_handler_ed_safe_shdload_done(int irq, void *dev_id) 445*711a3b87SLiu Ying { 446*711a3b87SLiu Ying struct dc_crtc *dc_crtc = dev_id; 447*711a3b87SLiu Ying 448*711a3b87SLiu Ying complete(&dc_crtc->ed_safe_shdload_done); 449*711a3b87SLiu Ying 450*711a3b87SLiu Ying return IRQ_HANDLED; 451*711a3b87SLiu Ying } 452*711a3b87SLiu Ying 453*711a3b87SLiu Ying static int dc_crtc_request_irqs(struct drm_device *drm, struct dc_crtc *dc_crtc) 454*711a3b87SLiu Ying { 455*711a3b87SLiu Ying struct { 456*711a3b87SLiu Ying struct device *dev; 457*711a3b87SLiu Ying unsigned int irq; 458*711a3b87SLiu Ying irqreturn_t (*irq_handler)(int irq, void *dev_id); 459*711a3b87SLiu Ying } irqs[DC_CRTC_IRQS] = { 460*711a3b87SLiu Ying { 461*711a3b87SLiu Ying dc_crtc->de->dev, 462*711a3b87SLiu Ying dc_crtc->irq_dec_framecomplete, 463*711a3b87SLiu Ying dc_crtc_irq_handler_dec_framecomplete, 464*711a3b87SLiu Ying }, { 465*711a3b87SLiu Ying dc_crtc->de->dev, 466*711a3b87SLiu Ying dc_crtc->irq_dec_seqcomplete, 467*711a3b87SLiu Ying dc_crtc_irq_handler_dec_seqcomplete_done, 468*711a3b87SLiu Ying }, { 469*711a3b87SLiu Ying dc_crtc->de->dev, 470*711a3b87SLiu Ying dc_crtc->irq_dec_shdload, 471*711a3b87SLiu Ying dc_crtc_irq_handler_dec_shdload_done, 472*711a3b87SLiu Ying }, { 473*711a3b87SLiu Ying dc_crtc->ed_cont->dev, 474*711a3b87SLiu Ying dc_crtc->irq_ed_cont_shdload, 475*711a3b87SLiu Ying dc_crtc_irq_handler_ed_cont_shdload_done, 476*711a3b87SLiu Ying }, { 477*711a3b87SLiu Ying dc_crtc->ed_safe->dev, 478*711a3b87SLiu Ying dc_crtc->irq_ed_safe_shdload, 479*711a3b87SLiu Ying dc_crtc_irq_handler_ed_safe_shdload_done, 480*711a3b87SLiu Ying }, 481*711a3b87SLiu Ying }; 482*711a3b87SLiu Ying int i, ret; 483*711a3b87SLiu Ying 484*711a3b87SLiu Ying for (i = 0; i < DC_CRTC_IRQS; i++) { 485*711a3b87SLiu Ying struct dc_crtc_irq *irq = &dc_crtc->irqs[i]; 486*711a3b87SLiu Ying 487*711a3b87SLiu Ying ret = devm_request_irq(irqs[i].dev, irqs[i].irq, 488*711a3b87SLiu Ying irqs[i].irq_handler, IRQF_NO_AUTOEN, 489*711a3b87SLiu Ying dev_name(irqs[i].dev), dc_crtc); 490*711a3b87SLiu Ying if (ret) { 491*711a3b87SLiu Ying dev_err(irqs[i].dev, "failed to request irq(%u): %d\n", 492*711a3b87SLiu Ying irqs[i].irq, ret); 493*711a3b87SLiu Ying return ret; 494*711a3b87SLiu Ying } 495*711a3b87SLiu Ying 496*711a3b87SLiu Ying irq->dc_crtc = dc_crtc; 497*711a3b87SLiu Ying irq->irq = irqs[i].irq; 498*711a3b87SLiu Ying } 499*711a3b87SLiu Ying 500*711a3b87SLiu Ying return 0; 501*711a3b87SLiu Ying } 502*711a3b87SLiu Ying 503*711a3b87SLiu Ying int dc_crtc_init(struct dc_drm_device *dc_drm, int crtc_index) 504*711a3b87SLiu Ying { 505*711a3b87SLiu Ying struct dc_crtc *dc_crtc = &dc_drm->dc_crtc[crtc_index]; 506*711a3b87SLiu Ying struct drm_device *drm = &dc_drm->base; 507*711a3b87SLiu Ying struct dc_de *de = dc_drm->de[crtc_index]; 508*711a3b87SLiu Ying struct dc_pe *pe = dc_drm->pe; 509*711a3b87SLiu Ying struct dc_plane *dc_primary; 510*711a3b87SLiu Ying int ret; 511*711a3b87SLiu Ying 512*711a3b87SLiu Ying dc_crtc->de = de; 513*711a3b87SLiu Ying 514*711a3b87SLiu Ying init_completion(&dc_crtc->dec_seqcomplete_done); 515*711a3b87SLiu Ying init_completion(&dc_crtc->dec_shdload_done); 516*711a3b87SLiu Ying init_completion(&dc_crtc->ed_cont_shdload_done); 517*711a3b87SLiu Ying init_completion(&dc_crtc->ed_safe_shdload_done); 518*711a3b87SLiu Ying 519*711a3b87SLiu Ying dc_crtc->cf_cont = pe->cf_cont[crtc_index]; 520*711a3b87SLiu Ying dc_crtc->cf_safe = pe->cf_safe[crtc_index]; 521*711a3b87SLiu Ying dc_crtc->ed_cont = pe->ed_cont[crtc_index]; 522*711a3b87SLiu Ying dc_crtc->ed_safe = pe->ed_safe[crtc_index]; 523*711a3b87SLiu Ying dc_crtc->fg = de->fg; 524*711a3b87SLiu Ying 525*711a3b87SLiu Ying dc_crtc->irq_dec_framecomplete = de->irq_framecomplete; 526*711a3b87SLiu Ying dc_crtc->irq_dec_seqcomplete = de->irq_seqcomplete; 527*711a3b87SLiu Ying dc_crtc->irq_dec_shdload = de->irq_shdload; 528*711a3b87SLiu Ying dc_crtc->irq_ed_safe_shdload = dc_crtc->ed_safe->irq_shdload; 529*711a3b87SLiu Ying dc_crtc->irq_ed_cont_shdload = dc_crtc->ed_cont->irq_shdload; 530*711a3b87SLiu Ying 531*711a3b87SLiu Ying dc_primary = &dc_drm->dc_primary[crtc_index]; 532*711a3b87SLiu Ying ret = dc_plane_init(dc_drm, dc_primary); 533*711a3b87SLiu Ying if (ret) { 534*711a3b87SLiu Ying dev_err(de->dev, "failed to initialize primary plane: %d\n", 535*711a3b87SLiu Ying ret); 536*711a3b87SLiu Ying return ret; 537*711a3b87SLiu Ying } 538*711a3b87SLiu Ying 539*711a3b87SLiu Ying drm_crtc_helper_add(&dc_crtc->base, &dc_helper_funcs); 540*711a3b87SLiu Ying 541*711a3b87SLiu Ying ret = drm_crtc_init_with_planes(drm, &dc_crtc->base, &dc_primary->base, 542*711a3b87SLiu Ying NULL, &dc_crtc_funcs, NULL); 543*711a3b87SLiu Ying if (ret) 544*711a3b87SLiu Ying dev_err(de->dev, "failed to add CRTC: %d\n", ret); 545*711a3b87SLiu Ying 546*711a3b87SLiu Ying return ret; 547*711a3b87SLiu Ying } 548*711a3b87SLiu Ying 549*711a3b87SLiu Ying int dc_crtc_post_init(struct dc_drm_device *dc_drm, int crtc_index) 550*711a3b87SLiu Ying { 551*711a3b87SLiu Ying struct dc_crtc *dc_crtc = &dc_drm->dc_crtc[crtc_index]; 552*711a3b87SLiu Ying struct drm_device *drm = &dc_drm->base; 553*711a3b87SLiu Ying 554*711a3b87SLiu Ying return dc_crtc_request_irqs(drm, dc_crtc); 555*711a3b87SLiu Ying } 556