xref: /linux/drivers/gpu/drm/imx/dc/dc-crtc.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
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