xref: /openbmc/linux/drivers/gpu/drm/armada/armada_crtc.c (revision 96f60e37dc66091bde8d5de136ff6fda09f2d799)
1*96f60e37SRussell King /*
2*96f60e37SRussell King  * Copyright (C) 2012 Russell King
3*96f60e37SRussell King  *  Rewritten from the dovefb driver, and Armada510 manuals.
4*96f60e37SRussell King  *
5*96f60e37SRussell King  * This program is free software; you can redistribute it and/or modify
6*96f60e37SRussell King  * it under the terms of the GNU General Public License version 2 as
7*96f60e37SRussell King  * published by the Free Software Foundation.
8*96f60e37SRussell King  */
9*96f60e37SRussell King #include <linux/clk.h>
10*96f60e37SRussell King #include <drm/drmP.h>
11*96f60e37SRussell King #include <drm/drm_crtc_helper.h>
12*96f60e37SRussell King #include "armada_crtc.h"
13*96f60e37SRussell King #include "armada_drm.h"
14*96f60e37SRussell King #include "armada_fb.h"
15*96f60e37SRussell King #include "armada_gem.h"
16*96f60e37SRussell King #include "armada_hw.h"
17*96f60e37SRussell King 
18*96f60e37SRussell King struct armada_frame_work {
19*96f60e37SRussell King 	struct drm_pending_vblank_event *event;
20*96f60e37SRussell King 	struct armada_regs regs[4];
21*96f60e37SRussell King 	struct drm_framebuffer *old_fb;
22*96f60e37SRussell King };
23*96f60e37SRussell King 
24*96f60e37SRussell King enum csc_mode {
25*96f60e37SRussell King 	CSC_AUTO = 0,
26*96f60e37SRussell King 	CSC_YUV_CCIR601 = 1,
27*96f60e37SRussell King 	CSC_YUV_CCIR709 = 2,
28*96f60e37SRussell King 	CSC_RGB_COMPUTER = 1,
29*96f60e37SRussell King 	CSC_RGB_STUDIO = 2,
30*96f60e37SRussell King };
31*96f60e37SRussell King 
32*96f60e37SRussell King /*
33*96f60e37SRussell King  * A note about interlacing.  Let's consider HDMI 1920x1080i.
34*96f60e37SRussell King  * The timing parameters we have from X are:
35*96f60e37SRussell King  *  Hact HsyA HsyI Htot  Vact VsyA VsyI Vtot
36*96f60e37SRussell King  *  1920 2448 2492 2640  1080 1084 1094 1125
37*96f60e37SRussell King  * Which get translated to:
38*96f60e37SRussell King  *  Hact HsyA HsyI Htot  Vact VsyA VsyI Vtot
39*96f60e37SRussell King  *  1920 2448 2492 2640   540  542  547  562
40*96f60e37SRussell King  *
41*96f60e37SRussell King  * This is how it is defined by CEA-861-D - line and pixel numbers are
42*96f60e37SRussell King  * referenced to the rising edge of VSYNC and HSYNC.  Total clocks per
43*96f60e37SRussell King  * line: 2640.  The odd frame, the first active line is at line 21, and
44*96f60e37SRussell King  * the even frame, the first active line is 584.
45*96f60e37SRussell King  *
46*96f60e37SRussell King  * LN:    560     561     562     563             567     568    569
47*96f60e37SRussell King  * DE:    ~~~|____________________________//__________________________
48*96f60e37SRussell King  * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____
49*96f60e37SRussell King  * VSYNC: _________________________|~~~~~~//~~~~~~~~~~~~~~~|__________
50*96f60e37SRussell King  *  22 blanking lines.  VSYNC at 1320 (referenced to the HSYNC rising edge).
51*96f60e37SRussell King  *
52*96f60e37SRussell King  * LN:    1123   1124    1125      1               5       6      7
53*96f60e37SRussell King  * DE:    ~~~|____________________________//__________________________
54*96f60e37SRussell King  * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____
55*96f60e37SRussell King  * VSYNC: ____________________|~~~~~~~~~~~//~~~~~~~~~~|_______________
56*96f60e37SRussell King  *  23 blanking lines
57*96f60e37SRussell King  *
58*96f60e37SRussell King  * The Armada LCD Controller line and pixel numbers are, like X timings,
59*96f60e37SRussell King  * referenced to the top left of the active frame.
60*96f60e37SRussell King  *
61*96f60e37SRussell King  * So, translating these to our LCD controller:
62*96f60e37SRussell King  *  Odd frame, 563 total lines, VSYNC at line 543-548, pixel 1128.
63*96f60e37SRussell King  *  Even frame, 562 total lines, VSYNC at line 542-547, pixel 2448.
64*96f60e37SRussell King  * Note: Vsync front porch remains constant!
65*96f60e37SRussell King  *
66*96f60e37SRussell King  * if (odd_frame) {
67*96f60e37SRussell King  *   vtotal = mode->crtc_vtotal + 1;
68*96f60e37SRussell King  *   vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay + 1;
69*96f60e37SRussell King  *   vhorizpos = mode->crtc_hsync_start - mode->crtc_htotal / 2
70*96f60e37SRussell King  * } else {
71*96f60e37SRussell King  *   vtotal = mode->crtc_vtotal;
72*96f60e37SRussell King  *   vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay;
73*96f60e37SRussell King  *   vhorizpos = mode->crtc_hsync_start;
74*96f60e37SRussell King  * }
75*96f60e37SRussell King  * vfrontporch = mode->crtc_vtotal - mode->crtc_vsync_end;
76*96f60e37SRussell King  *
77*96f60e37SRussell King  * So, we need to reprogram these registers on each vsync event:
78*96f60e37SRussell King  *  LCD_SPU_V_PORCH, LCD_SPU_ADV_REG, LCD_SPUT_V_H_TOTAL
79*96f60e37SRussell King  *
80*96f60e37SRussell King  * Note: we do not use the frame done interrupts because these appear
81*96f60e37SRussell King  * to happen too early, and lead to jitter on the display (presumably
82*96f60e37SRussell King  * they occur at the end of the last active line, before the vsync back
83*96f60e37SRussell King  * porch, which we're reprogramming.)
84*96f60e37SRussell King  */
85*96f60e37SRussell King 
86*96f60e37SRussell King void
87*96f60e37SRussell King armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs)
88*96f60e37SRussell King {
89*96f60e37SRussell King 	while (regs->offset != ~0) {
90*96f60e37SRussell King 		void __iomem *reg = dcrtc->base + regs->offset;
91*96f60e37SRussell King 		uint32_t val;
92*96f60e37SRussell King 
93*96f60e37SRussell King 		val = regs->mask;
94*96f60e37SRussell King 		if (val != 0)
95*96f60e37SRussell King 			val &= readl_relaxed(reg);
96*96f60e37SRussell King 		writel_relaxed(val | regs->val, reg);
97*96f60e37SRussell King 		++regs;
98*96f60e37SRussell King 	}
99*96f60e37SRussell King }
100*96f60e37SRussell King 
101*96f60e37SRussell King #define dpms_blanked(dpms)	((dpms) != DRM_MODE_DPMS_ON)
102*96f60e37SRussell King 
103*96f60e37SRussell King static void armada_drm_crtc_update(struct armada_crtc *dcrtc)
104*96f60e37SRussell King {
105*96f60e37SRussell King 	uint32_t dumb_ctrl;
106*96f60e37SRussell King 
107*96f60e37SRussell King 	dumb_ctrl = dcrtc->cfg_dumb_ctrl;
108*96f60e37SRussell King 
109*96f60e37SRussell King 	if (!dpms_blanked(dcrtc->dpms))
110*96f60e37SRussell King 		dumb_ctrl |= CFG_DUMB_ENA;
111*96f60e37SRussell King 
112*96f60e37SRussell King 	/*
113*96f60e37SRussell King 	 * When the dumb interface isn't in DUMB24_RGB888_0 mode, it might
114*96f60e37SRussell King 	 * be using SPI or GPIO.  If we set this to DUMB_BLANK, we will
115*96f60e37SRussell King 	 * force LCD_D[23:0] to output blank color, overriding the GPIO or
116*96f60e37SRussell King 	 * SPI usage.  So leave it as-is unless in DUMB24_RGB888_0 mode.
117*96f60e37SRussell King 	 */
118*96f60e37SRussell King 	if (dpms_blanked(dcrtc->dpms) &&
119*96f60e37SRussell King 	    (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) {
120*96f60e37SRussell King 		dumb_ctrl &= ~DUMB_MASK;
121*96f60e37SRussell King 		dumb_ctrl |= DUMB_BLANK;
122*96f60e37SRussell King 	}
123*96f60e37SRussell King 
124*96f60e37SRussell King 	/*
125*96f60e37SRussell King 	 * The documentation doesn't indicate what the normal state of
126*96f60e37SRussell King 	 * the sync signals are.  Sebastian Hesselbart kindly probed
127*96f60e37SRussell King 	 * these signals on his board to determine their state.
128*96f60e37SRussell King 	 *
129*96f60e37SRussell King 	 * The non-inverted state of the sync signals is active high.
130*96f60e37SRussell King 	 * Setting these bits makes the appropriate signal active low.
131*96f60e37SRussell King 	 */
132*96f60e37SRussell King 	if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NCSYNC)
133*96f60e37SRussell King 		dumb_ctrl |= CFG_INV_CSYNC;
134*96f60e37SRussell King 	if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NHSYNC)
135*96f60e37SRussell King 		dumb_ctrl |= CFG_INV_HSYNC;
136*96f60e37SRussell King 	if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NVSYNC)
137*96f60e37SRussell King 		dumb_ctrl |= CFG_INV_VSYNC;
138*96f60e37SRussell King 
139*96f60e37SRussell King 	if (dcrtc->dumb_ctrl != dumb_ctrl) {
140*96f60e37SRussell King 		dcrtc->dumb_ctrl = dumb_ctrl;
141*96f60e37SRussell King 		writel_relaxed(dumb_ctrl, dcrtc->base + LCD_SPU_DUMB_CTRL);
142*96f60e37SRussell King 	}
143*96f60e37SRussell King }
144*96f60e37SRussell King 
145*96f60e37SRussell King static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb,
146*96f60e37SRussell King 	int x, int y, struct armada_regs *regs, bool interlaced)
147*96f60e37SRussell King {
148*96f60e37SRussell King 	struct armada_gem_object *obj = drm_fb_obj(fb);
149*96f60e37SRussell King 	unsigned pitch = fb->pitches[0];
150*96f60e37SRussell King 	unsigned offset = y * pitch + x * fb->bits_per_pixel / 8;
151*96f60e37SRussell King 	uint32_t addr_odd, addr_even;
152*96f60e37SRussell King 	unsigned i = 0;
153*96f60e37SRussell King 
154*96f60e37SRussell King 	DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n",
155*96f60e37SRussell King 		pitch, x, y, fb->bits_per_pixel);
156*96f60e37SRussell King 
157*96f60e37SRussell King 	addr_odd = addr_even = obj->dev_addr + offset;
158*96f60e37SRussell King 
159*96f60e37SRussell King 	if (interlaced) {
160*96f60e37SRussell King 		addr_even += pitch;
161*96f60e37SRussell King 		pitch *= 2;
162*96f60e37SRussell King 	}
163*96f60e37SRussell King 
164*96f60e37SRussell King 	/* write offset, base, and pitch */
165*96f60e37SRussell King 	armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0);
166*96f60e37SRussell King 	armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1);
167*96f60e37SRussell King 	armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH);
168*96f60e37SRussell King 
169*96f60e37SRussell King 	return i;
170*96f60e37SRussell King }
171*96f60e37SRussell King 
172*96f60e37SRussell King static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc,
173*96f60e37SRussell King 	struct armada_frame_work *work)
174*96f60e37SRussell King {
175*96f60e37SRussell King 	struct drm_device *dev = dcrtc->crtc.dev;
176*96f60e37SRussell King 	unsigned long flags;
177*96f60e37SRussell King 	int ret;
178*96f60e37SRussell King 
179*96f60e37SRussell King 	ret = drm_vblank_get(dev, dcrtc->num);
180*96f60e37SRussell King 	if (ret) {
181*96f60e37SRussell King 		DRM_ERROR("failed to acquire vblank counter\n");
182*96f60e37SRussell King 		return ret;
183*96f60e37SRussell King 	}
184*96f60e37SRussell King 
185*96f60e37SRussell King 	spin_lock_irqsave(&dev->event_lock, flags);
186*96f60e37SRussell King 	if (!dcrtc->frame_work)
187*96f60e37SRussell King 		dcrtc->frame_work = work;
188*96f60e37SRussell King 	else
189*96f60e37SRussell King 		ret = -EBUSY;
190*96f60e37SRussell King 	spin_unlock_irqrestore(&dev->event_lock, flags);
191*96f60e37SRussell King 
192*96f60e37SRussell King 	if (ret)
193*96f60e37SRussell King 		drm_vblank_put(dev, dcrtc->num);
194*96f60e37SRussell King 
195*96f60e37SRussell King 	return ret;
196*96f60e37SRussell King }
197*96f60e37SRussell King 
198*96f60e37SRussell King static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc)
199*96f60e37SRussell King {
200*96f60e37SRussell King 	struct drm_device *dev = dcrtc->crtc.dev;
201*96f60e37SRussell King 	struct armada_frame_work *work = dcrtc->frame_work;
202*96f60e37SRussell King 
203*96f60e37SRussell King 	dcrtc->frame_work = NULL;
204*96f60e37SRussell King 
205*96f60e37SRussell King 	armada_drm_crtc_update_regs(dcrtc, work->regs);
206*96f60e37SRussell King 
207*96f60e37SRussell King 	if (work->event)
208*96f60e37SRussell King 		drm_send_vblank_event(dev, dcrtc->num, work->event);
209*96f60e37SRussell King 
210*96f60e37SRussell King 	drm_vblank_put(dev, dcrtc->num);
211*96f60e37SRussell King 
212*96f60e37SRussell King 	/* Finally, queue the process-half of the cleanup. */
213*96f60e37SRussell King 	__armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb);
214*96f60e37SRussell King 	kfree(work);
215*96f60e37SRussell King }
216*96f60e37SRussell King 
217*96f60e37SRussell King static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
218*96f60e37SRussell King 	struct drm_framebuffer *fb, bool force)
219*96f60e37SRussell King {
220*96f60e37SRussell King 	struct armada_frame_work *work;
221*96f60e37SRussell King 
222*96f60e37SRussell King 	if (!fb)
223*96f60e37SRussell King 		return;
224*96f60e37SRussell King 
225*96f60e37SRussell King 	if (force) {
226*96f60e37SRussell King 		/* Display is disabled, so just drop the old fb */
227*96f60e37SRussell King 		drm_framebuffer_unreference(fb);
228*96f60e37SRussell King 		return;
229*96f60e37SRussell King 	}
230*96f60e37SRussell King 
231*96f60e37SRussell King 	work = kmalloc(sizeof(*work), GFP_KERNEL);
232*96f60e37SRussell King 	if (work) {
233*96f60e37SRussell King 		int i = 0;
234*96f60e37SRussell King 		work->event = NULL;
235*96f60e37SRussell King 		work->old_fb = fb;
236*96f60e37SRussell King 		armada_reg_queue_end(work->regs, i);
237*96f60e37SRussell King 
238*96f60e37SRussell King 		if (armada_drm_crtc_queue_frame_work(dcrtc, work) == 0)
239*96f60e37SRussell King 			return;
240*96f60e37SRussell King 
241*96f60e37SRussell King 		kfree(work);
242*96f60e37SRussell King 	}
243*96f60e37SRussell King 
244*96f60e37SRussell King 	/*
245*96f60e37SRussell King 	 * Oops - just drop the reference immediately and hope for
246*96f60e37SRussell King 	 * the best.  The worst that will happen is the buffer gets
247*96f60e37SRussell King 	 * reused before it has finished being displayed.
248*96f60e37SRussell King 	 */
249*96f60e37SRussell King 	drm_framebuffer_unreference(fb);
250*96f60e37SRussell King }
251*96f60e37SRussell King 
252*96f60e37SRussell King static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
253*96f60e37SRussell King {
254*96f60e37SRussell King 	struct drm_device *dev = dcrtc->crtc.dev;
255*96f60e37SRussell King 
256*96f60e37SRussell King 	/*
257*96f60e37SRussell King 	 * Tell the DRM core that vblank IRQs aren't going to happen for
258*96f60e37SRussell King 	 * a while.  This cleans up any pending vblank events for us.
259*96f60e37SRussell King 	 */
260*96f60e37SRussell King 	drm_vblank_off(dev, dcrtc->num);
261*96f60e37SRussell King 
262*96f60e37SRussell King 	/* Handle any pending flip event. */
263*96f60e37SRussell King 	spin_lock_irq(&dev->event_lock);
264*96f60e37SRussell King 	if (dcrtc->frame_work)
265*96f60e37SRussell King 		armada_drm_crtc_complete_frame_work(dcrtc);
266*96f60e37SRussell King 	spin_unlock_irq(&dev->event_lock);
267*96f60e37SRussell King }
268*96f60e37SRussell King 
269*96f60e37SRussell King void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
270*96f60e37SRussell King 	int idx)
271*96f60e37SRussell King {
272*96f60e37SRussell King }
273*96f60e37SRussell King 
274*96f60e37SRussell King void armada_drm_crtc_gamma_get(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
275*96f60e37SRussell King 	int idx)
276*96f60e37SRussell King {
277*96f60e37SRussell King }
278*96f60e37SRussell King 
279*96f60e37SRussell King /* The mode_config.mutex will be held for this call */
280*96f60e37SRussell King static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms)
281*96f60e37SRussell King {
282*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
283*96f60e37SRussell King 
284*96f60e37SRussell King 	if (dcrtc->dpms != dpms) {
285*96f60e37SRussell King 		dcrtc->dpms = dpms;
286*96f60e37SRussell King 		armada_drm_crtc_update(dcrtc);
287*96f60e37SRussell King 		if (dpms_blanked(dpms))
288*96f60e37SRussell King 			armada_drm_vblank_off(dcrtc);
289*96f60e37SRussell King 	}
290*96f60e37SRussell King }
291*96f60e37SRussell King 
292*96f60e37SRussell King /*
293*96f60e37SRussell King  * Prepare for a mode set.  Turn off overlay to ensure that we don't end
294*96f60e37SRussell King  * up with the overlay size being bigger than the active screen size.
295*96f60e37SRussell King  * We rely upon X refreshing this state after the mode set has completed.
296*96f60e37SRussell King  *
297*96f60e37SRussell King  * The mode_config.mutex will be held for this call
298*96f60e37SRussell King  */
299*96f60e37SRussell King static void armada_drm_crtc_prepare(struct drm_crtc *crtc)
300*96f60e37SRussell King {
301*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
302*96f60e37SRussell King 	struct drm_plane *plane;
303*96f60e37SRussell King 
304*96f60e37SRussell King 	/*
305*96f60e37SRussell King 	 * If we have an overlay plane associated with this CRTC, disable
306*96f60e37SRussell King 	 * it before the modeset to avoid its coordinates being outside
307*96f60e37SRussell King 	 * the new mode parameters.  DRM doesn't provide help with this.
308*96f60e37SRussell King 	 */
309*96f60e37SRussell King 	plane = dcrtc->plane;
310*96f60e37SRussell King 	if (plane) {
311*96f60e37SRussell King 		struct drm_framebuffer *fb = plane->fb;
312*96f60e37SRussell King 
313*96f60e37SRussell King 		plane->funcs->disable_plane(plane);
314*96f60e37SRussell King 		plane->fb = NULL;
315*96f60e37SRussell King 		plane->crtc = NULL;
316*96f60e37SRussell King 		drm_framebuffer_unreference(fb);
317*96f60e37SRussell King 	}
318*96f60e37SRussell King }
319*96f60e37SRussell King 
320*96f60e37SRussell King /* The mode_config.mutex will be held for this call */
321*96f60e37SRussell King static void armada_drm_crtc_commit(struct drm_crtc *crtc)
322*96f60e37SRussell King {
323*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
324*96f60e37SRussell King 
325*96f60e37SRussell King 	if (dcrtc->dpms != DRM_MODE_DPMS_ON) {
326*96f60e37SRussell King 		dcrtc->dpms = DRM_MODE_DPMS_ON;
327*96f60e37SRussell King 		armada_drm_crtc_update(dcrtc);
328*96f60e37SRussell King 	}
329*96f60e37SRussell King }
330*96f60e37SRussell King 
331*96f60e37SRussell King /* The mode_config.mutex will be held for this call */
332*96f60e37SRussell King static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
333*96f60e37SRussell King 	const struct drm_display_mode *mode, struct drm_display_mode *adj)
334*96f60e37SRussell King {
335*96f60e37SRussell King 	struct armada_private *priv = crtc->dev->dev_private;
336*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
337*96f60e37SRussell King 	int ret;
338*96f60e37SRussell King 
339*96f60e37SRussell King 	/* We can't do interlaced modes if we don't have the SPU_ADV_REG */
340*96f60e37SRussell King 	if (!priv->variant->has_spu_adv_reg &&
341*96f60e37SRussell King 	    adj->flags & DRM_MODE_FLAG_INTERLACE)
342*96f60e37SRussell King 		return false;
343*96f60e37SRussell King 
344*96f60e37SRussell King 	/* Check whether the display mode is possible */
345*96f60e37SRussell King 	ret = priv->variant->crtc_compute_clock(dcrtc, adj, NULL);
346*96f60e37SRussell King 	if (ret)
347*96f60e37SRussell King 		return false;
348*96f60e37SRussell King 
349*96f60e37SRussell King 	return true;
350*96f60e37SRussell King }
351*96f60e37SRussell King 
352*96f60e37SRussell King void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
353*96f60e37SRussell King {
354*96f60e37SRussell King 	struct armada_vbl_event *e, *n;
355*96f60e37SRussell King 	void __iomem *base = dcrtc->base;
356*96f60e37SRussell King 
357*96f60e37SRussell King 	if (stat & DMA_FF_UNDERFLOW)
358*96f60e37SRussell King 		DRM_ERROR("video underflow on crtc %u\n", dcrtc->num);
359*96f60e37SRussell King 	if (stat & GRA_FF_UNDERFLOW)
360*96f60e37SRussell King 		DRM_ERROR("graphics underflow on crtc %u\n", dcrtc->num);
361*96f60e37SRussell King 
362*96f60e37SRussell King 	if (stat & VSYNC_IRQ)
363*96f60e37SRussell King 		drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num);
364*96f60e37SRussell King 
365*96f60e37SRussell King 	spin_lock(&dcrtc->irq_lock);
366*96f60e37SRussell King 
367*96f60e37SRussell King 	list_for_each_entry_safe(e, n, &dcrtc->vbl_list, node) {
368*96f60e37SRussell King 		list_del_init(&e->node);
369*96f60e37SRussell King 		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
370*96f60e37SRussell King 		e->fn(dcrtc, e->data);
371*96f60e37SRussell King 	}
372*96f60e37SRussell King 
373*96f60e37SRussell King 	if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) {
374*96f60e37SRussell King 		int i = stat & GRA_FRAME_IRQ0 ? 0 : 1;
375*96f60e37SRussell King 		uint32_t val;
376*96f60e37SRussell King 
377*96f60e37SRussell King 		writel_relaxed(dcrtc->v[i].spu_v_porch, base + LCD_SPU_V_PORCH);
378*96f60e37SRussell King 		writel_relaxed(dcrtc->v[i].spu_v_h_total,
379*96f60e37SRussell King 			       base + LCD_SPUT_V_H_TOTAL);
380*96f60e37SRussell King 
381*96f60e37SRussell King 		val = readl_relaxed(base + LCD_SPU_ADV_REG);
382*96f60e37SRussell King 		val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN);
383*96f60e37SRussell King 		val |= dcrtc->v[i].spu_adv_reg;
384*96f60e37SRussell King 		writel_relaxed(val, dcrtc->base + LCD_SPU_ADV_REG);
385*96f60e37SRussell King 	}
386*96f60e37SRussell King 	spin_unlock(&dcrtc->irq_lock);
387*96f60e37SRussell King 
388*96f60e37SRussell King 	if (stat & GRA_FRAME_IRQ) {
389*96f60e37SRussell King 		struct drm_device *dev = dcrtc->crtc.dev;
390*96f60e37SRussell King 
391*96f60e37SRussell King 		spin_lock(&dev->event_lock);
392*96f60e37SRussell King 		if (dcrtc->frame_work)
393*96f60e37SRussell King 			armada_drm_crtc_complete_frame_work(dcrtc);
394*96f60e37SRussell King 		spin_unlock(&dev->event_lock);
395*96f60e37SRussell King 
396*96f60e37SRussell King 		wake_up(&dcrtc->frame_wait);
397*96f60e37SRussell King 	}
398*96f60e37SRussell King }
399*96f60e37SRussell King 
400*96f60e37SRussell King /* These are locked by dev->vbl_lock */
401*96f60e37SRussell King void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
402*96f60e37SRussell King {
403*96f60e37SRussell King 	if (dcrtc->irq_ena & mask) {
404*96f60e37SRussell King 		dcrtc->irq_ena &= ~mask;
405*96f60e37SRussell King 		writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
406*96f60e37SRussell King 	}
407*96f60e37SRussell King }
408*96f60e37SRussell King 
409*96f60e37SRussell King void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask)
410*96f60e37SRussell King {
411*96f60e37SRussell King 	if ((dcrtc->irq_ena & mask) != mask) {
412*96f60e37SRussell King 		dcrtc->irq_ena |= mask;
413*96f60e37SRussell King 		writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
414*96f60e37SRussell King 		if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask)
415*96f60e37SRussell King 			writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
416*96f60e37SRussell King 	}
417*96f60e37SRussell King }
418*96f60e37SRussell King 
419*96f60e37SRussell King static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc)
420*96f60e37SRussell King {
421*96f60e37SRussell King 	struct drm_display_mode *adj = &dcrtc->crtc.mode;
422*96f60e37SRussell King 	uint32_t val = 0;
423*96f60e37SRussell King 
424*96f60e37SRussell King 	if (dcrtc->csc_yuv_mode == CSC_YUV_CCIR709)
425*96f60e37SRussell King 		val |= CFG_CSC_YUV_CCIR709;
426*96f60e37SRussell King 	if (dcrtc->csc_rgb_mode == CSC_RGB_STUDIO)
427*96f60e37SRussell King 		val |= CFG_CSC_RGB_STUDIO;
428*96f60e37SRussell King 
429*96f60e37SRussell King 	/*
430*96f60e37SRussell King 	 * In auto mode, set the colorimetry, based upon the HDMI spec.
431*96f60e37SRussell King 	 * 1280x720p, 1920x1080p and 1920x1080i use ITU709, others use
432*96f60e37SRussell King 	 * ITU601.  It may be more appropriate to set this depending on
433*96f60e37SRussell King 	 * the source - but what if the graphic frame is YUV and the
434*96f60e37SRussell King 	 * video frame is RGB?
435*96f60e37SRussell King 	 */
436*96f60e37SRussell King 	if ((adj->hdisplay == 1280 && adj->vdisplay == 720 &&
437*96f60e37SRussell King 	     !(adj->flags & DRM_MODE_FLAG_INTERLACE)) ||
438*96f60e37SRussell King 	    (adj->hdisplay == 1920 && adj->vdisplay == 1080)) {
439*96f60e37SRussell King 		if (dcrtc->csc_yuv_mode == CSC_AUTO)
440*96f60e37SRussell King 			val |= CFG_CSC_YUV_CCIR709;
441*96f60e37SRussell King 	}
442*96f60e37SRussell King 
443*96f60e37SRussell King 	/*
444*96f60e37SRussell King 	 * We assume we're connected to a TV-like device, so the YUV->RGB
445*96f60e37SRussell King 	 * conversion should produce a limited range.  We should set this
446*96f60e37SRussell King 	 * depending on the connectors attached to this CRTC, and what
447*96f60e37SRussell King 	 * kind of device they report being connected.
448*96f60e37SRussell King 	 */
449*96f60e37SRussell King 	if (dcrtc->csc_rgb_mode == CSC_AUTO)
450*96f60e37SRussell King 		val |= CFG_CSC_RGB_STUDIO;
451*96f60e37SRussell King 
452*96f60e37SRussell King 	return val;
453*96f60e37SRussell King }
454*96f60e37SRussell King 
455*96f60e37SRussell King /* The mode_config.mutex will be held for this call */
456*96f60e37SRussell King static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
457*96f60e37SRussell King 	struct drm_display_mode *mode, struct drm_display_mode *adj,
458*96f60e37SRussell King 	int x, int y, struct drm_framebuffer *old_fb)
459*96f60e37SRussell King {
460*96f60e37SRussell King 	struct armada_private *priv = crtc->dev->dev_private;
461*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
462*96f60e37SRussell King 	struct armada_regs regs[17];
463*96f60e37SRussell King 	uint32_t lm, rm, tm, bm, val, sclk;
464*96f60e37SRussell King 	unsigned long flags;
465*96f60e37SRussell King 	unsigned i;
466*96f60e37SRussell King 	bool interlaced;
467*96f60e37SRussell King 
468*96f60e37SRussell King 	drm_framebuffer_reference(crtc->fb);
469*96f60e37SRussell King 
470*96f60e37SRussell King 	interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
471*96f60e37SRussell King 
472*96f60e37SRussell King 	i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced);
473*96f60e37SRussell King 
474*96f60e37SRussell King 	rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
475*96f60e37SRussell King 	lm = adj->crtc_htotal - adj->crtc_hsync_end;
476*96f60e37SRussell King 	bm = adj->crtc_vsync_start - adj->crtc_vdisplay;
477*96f60e37SRussell King 	tm = adj->crtc_vtotal - adj->crtc_vsync_end;
478*96f60e37SRussell King 
479*96f60e37SRussell King 	DRM_DEBUG_DRIVER("H: %d %d %d %d lm %d rm %d\n",
480*96f60e37SRussell King 		adj->crtc_hdisplay,
481*96f60e37SRussell King 		adj->crtc_hsync_start,
482*96f60e37SRussell King 		adj->crtc_hsync_end,
483*96f60e37SRussell King 		adj->crtc_htotal, lm, rm);
484*96f60e37SRussell King 	DRM_DEBUG_DRIVER("V: %d %d %d %d tm %d bm %d\n",
485*96f60e37SRussell King 		adj->crtc_vdisplay,
486*96f60e37SRussell King 		adj->crtc_vsync_start,
487*96f60e37SRussell King 		adj->crtc_vsync_end,
488*96f60e37SRussell King 		adj->crtc_vtotal, tm, bm);
489*96f60e37SRussell King 
490*96f60e37SRussell King 	/* Wait for pending flips to complete */
491*96f60e37SRussell King 	wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
492*96f60e37SRussell King 
493*96f60e37SRussell King 	drm_vblank_pre_modeset(crtc->dev, dcrtc->num);
494*96f60e37SRussell King 
495*96f60e37SRussell King 	crtc->mode = *adj;
496*96f60e37SRussell King 
497*96f60e37SRussell King 	val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA;
498*96f60e37SRussell King 	if (val != dcrtc->dumb_ctrl) {
499*96f60e37SRussell King 		dcrtc->dumb_ctrl = val;
500*96f60e37SRussell King 		writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL);
501*96f60e37SRussell King 	}
502*96f60e37SRussell King 
503*96f60e37SRussell King 	/* Now compute the divider for real */
504*96f60e37SRussell King 	priv->variant->crtc_compute_clock(dcrtc, adj, &sclk);
505*96f60e37SRussell King 
506*96f60e37SRussell King 	/* Ensure graphic fifo is enabled */
507*96f60e37SRussell King 	armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1);
508*96f60e37SRussell King 	armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV);
509*96f60e37SRussell King 
510*96f60e37SRussell King 	if (interlaced ^ dcrtc->interlaced) {
511*96f60e37SRussell King 		if (adj->flags & DRM_MODE_FLAG_INTERLACE)
512*96f60e37SRussell King 			drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
513*96f60e37SRussell King 		else
514*96f60e37SRussell King 			drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
515*96f60e37SRussell King 		dcrtc->interlaced = interlaced;
516*96f60e37SRussell King 	}
517*96f60e37SRussell King 
518*96f60e37SRussell King 	spin_lock_irqsave(&dcrtc->irq_lock, flags);
519*96f60e37SRussell King 
520*96f60e37SRussell King 	/* Even interlaced/progressive frame */
521*96f60e37SRussell King 	dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |
522*96f60e37SRussell King 				    adj->crtc_htotal;
523*96f60e37SRussell King 	dcrtc->v[1].spu_v_porch = tm << 16 | bm;
524*96f60e37SRussell King 	val = adj->crtc_hsync_start;
525*96f60e37SRussell King 	dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN;
526*96f60e37SRussell King 
527*96f60e37SRussell King 	if (interlaced) {
528*96f60e37SRussell King 		/* Odd interlaced frame */
529*96f60e37SRussell King 		dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total +
530*96f60e37SRussell King 						(1 << 16);
531*96f60e37SRussell King 		dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1;
532*96f60e37SRussell King 		val = adj->crtc_hsync_start - adj->crtc_htotal / 2;
533*96f60e37SRussell King 		dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN;
534*96f60e37SRussell King 	} else {
535*96f60e37SRussell King 		dcrtc->v[0] = dcrtc->v[1];
536*96f60e37SRussell King 	}
537*96f60e37SRussell King 
538*96f60e37SRussell King 	val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay;
539*96f60e37SRussell King 
540*96f60e37SRussell King 	armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE);
541*96f60e37SRussell King 	armada_reg_queue_set(regs, i, val, LCD_SPU_GRA_HPXL_VLN);
542*96f60e37SRussell King 	armada_reg_queue_set(regs, i, val, LCD_SPU_GZM_HPXL_VLN);
543*96f60e37SRussell King 	armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH);
544*96f60e37SRussell King 	armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH);
545*96f60e37SRussell King 	armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
546*96f60e37SRussell King 			   LCD_SPUT_V_H_TOTAL);
547*96f60e37SRussell King 
548*96f60e37SRussell King 	if (priv->variant->has_spu_adv_reg)
549*96f60e37SRussell King 		armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg,
550*96f60e37SRussell King 				     ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF |
551*96f60e37SRussell King 				     ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
552*96f60e37SRussell King 
553*96f60e37SRussell King 	val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
554*96f60e37SRussell King 	val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
555*96f60e37SRussell King 	val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod);
556*96f60e37SRussell King 
557*96f60e37SRussell King 	if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420)
558*96f60e37SRussell King 		val |= CFG_PALETTE_ENA;
559*96f60e37SRussell King 
560*96f60e37SRussell King 	if (interlaced)
561*96f60e37SRussell King 		val |= CFG_GRA_FTOGGLE;
562*96f60e37SRussell King 
563*96f60e37SRussell King 	armada_reg_queue_mod(regs, i, val, CFG_GRAFORMAT |
564*96f60e37SRussell King 			     CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
565*96f60e37SRussell King 					 CFG_SWAPYU | CFG_YUV2RGB) |
566*96f60e37SRussell King 			     CFG_PALETTE_ENA | CFG_GRA_FTOGGLE,
567*96f60e37SRussell King 			     LCD_SPU_DMA_CTRL0);
568*96f60e37SRussell King 
569*96f60e37SRussell King 	val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0;
570*96f60e37SRussell King 	armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1);
571*96f60e37SRussell King 
572*96f60e37SRussell King 	val = dcrtc->spu_iopad_ctrl | armada_drm_crtc_calculate_csc(dcrtc);
573*96f60e37SRussell King 	armada_reg_queue_set(regs, i, val, LCD_SPU_IOPAD_CONTROL);
574*96f60e37SRussell King 	armada_reg_queue_end(regs, i);
575*96f60e37SRussell King 
576*96f60e37SRussell King 	armada_drm_crtc_update_regs(dcrtc, regs);
577*96f60e37SRussell King 	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
578*96f60e37SRussell King 
579*96f60e37SRussell King 	armada_drm_crtc_update(dcrtc);
580*96f60e37SRussell King 
581*96f60e37SRussell King 	drm_vblank_post_modeset(crtc->dev, dcrtc->num);
582*96f60e37SRussell King 	armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms));
583*96f60e37SRussell King 
584*96f60e37SRussell King 	return 0;
585*96f60e37SRussell King }
586*96f60e37SRussell King 
587*96f60e37SRussell King /* The mode_config.mutex will be held for this call */
588*96f60e37SRussell King static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
589*96f60e37SRussell King 	struct drm_framebuffer *old_fb)
590*96f60e37SRussell King {
591*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
592*96f60e37SRussell King 	struct armada_regs regs[4];
593*96f60e37SRussell King 	unsigned i;
594*96f60e37SRussell King 
595*96f60e37SRussell King 	i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs,
596*96f60e37SRussell King 				    dcrtc->interlaced);
597*96f60e37SRussell King 	armada_reg_queue_end(regs, i);
598*96f60e37SRussell King 
599*96f60e37SRussell King 	/* Wait for pending flips to complete */
600*96f60e37SRussell King 	wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
601*96f60e37SRussell King 
602*96f60e37SRussell King 	/* Take a reference to the new fb as we're using it */
603*96f60e37SRussell King 	drm_framebuffer_reference(crtc->fb);
604*96f60e37SRussell King 
605*96f60e37SRussell King 	/* Update the base in the CRTC */
606*96f60e37SRussell King 	armada_drm_crtc_update_regs(dcrtc, regs);
607*96f60e37SRussell King 
608*96f60e37SRussell King 	/* Drop our previously held reference */
609*96f60e37SRussell King 	armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms));
610*96f60e37SRussell King 
611*96f60e37SRussell King 	return 0;
612*96f60e37SRussell King }
613*96f60e37SRussell King 
614*96f60e37SRussell King static void armada_drm_crtc_load_lut(struct drm_crtc *crtc)
615*96f60e37SRussell King {
616*96f60e37SRussell King }
617*96f60e37SRussell King 
618*96f60e37SRussell King /* The mode_config.mutex will be held for this call */
619*96f60e37SRussell King static void armada_drm_crtc_disable(struct drm_crtc *crtc)
620*96f60e37SRussell King {
621*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
622*96f60e37SRussell King 
623*96f60e37SRussell King 	armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
624*96f60e37SRussell King 	armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true);
625*96f60e37SRussell King 
626*96f60e37SRussell King 	/* Power down most RAMs and FIFOs */
627*96f60e37SRussell King 	writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
628*96f60e37SRussell King 		       CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
629*96f60e37SRussell King 		       CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
630*96f60e37SRussell King }
631*96f60e37SRussell King 
632*96f60e37SRussell King static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
633*96f60e37SRussell King 	.dpms		= armada_drm_crtc_dpms,
634*96f60e37SRussell King 	.prepare	= armada_drm_crtc_prepare,
635*96f60e37SRussell King 	.commit		= armada_drm_crtc_commit,
636*96f60e37SRussell King 	.mode_fixup	= armada_drm_crtc_mode_fixup,
637*96f60e37SRussell King 	.mode_set	= armada_drm_crtc_mode_set,
638*96f60e37SRussell King 	.mode_set_base	= armada_drm_crtc_mode_set_base,
639*96f60e37SRussell King 	.load_lut	= armada_drm_crtc_load_lut,
640*96f60e37SRussell King 	.disable	= armada_drm_crtc_disable,
641*96f60e37SRussell King };
642*96f60e37SRussell King 
643*96f60e37SRussell King static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
644*96f60e37SRussell King {
645*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
646*96f60e37SRussell King 	struct armada_private *priv = crtc->dev->dev_private;
647*96f60e37SRussell King 
648*96f60e37SRussell King 	priv->dcrtc[dcrtc->num] = NULL;
649*96f60e37SRussell King 	drm_crtc_cleanup(&dcrtc->crtc);
650*96f60e37SRussell King 
651*96f60e37SRussell King 	if (!IS_ERR(dcrtc->clk))
652*96f60e37SRussell King 		clk_disable_unprepare(dcrtc->clk);
653*96f60e37SRussell King 
654*96f60e37SRussell King 	kfree(dcrtc);
655*96f60e37SRussell King }
656*96f60e37SRussell King 
657*96f60e37SRussell King /*
658*96f60e37SRussell King  * The mode_config lock is held here, to prevent races between this
659*96f60e37SRussell King  * and a mode_set.
660*96f60e37SRussell King  */
661*96f60e37SRussell King static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
662*96f60e37SRussell King 	struct drm_framebuffer *fb, struct drm_pending_vblank_event *event)
663*96f60e37SRussell King {
664*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
665*96f60e37SRussell King 	struct armada_frame_work *work;
666*96f60e37SRussell King 	struct drm_device *dev = crtc->dev;
667*96f60e37SRussell King 	unsigned long flags;
668*96f60e37SRussell King 	unsigned i;
669*96f60e37SRussell King 	int ret;
670*96f60e37SRussell King 
671*96f60e37SRussell King 	/* We don't support changing the pixel format */
672*96f60e37SRussell King 	if (fb->pixel_format != crtc->fb->pixel_format)
673*96f60e37SRussell King 		return -EINVAL;
674*96f60e37SRussell King 
675*96f60e37SRussell King 	work = kmalloc(sizeof(*work), GFP_KERNEL);
676*96f60e37SRussell King 	if (!work)
677*96f60e37SRussell King 		return -ENOMEM;
678*96f60e37SRussell King 
679*96f60e37SRussell King 	work->event = event;
680*96f60e37SRussell King 	work->old_fb = dcrtc->crtc.fb;
681*96f60e37SRussell King 
682*96f60e37SRussell King 	i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs,
683*96f60e37SRussell King 				    dcrtc->interlaced);
684*96f60e37SRussell King 	armada_reg_queue_end(work->regs, i);
685*96f60e37SRussell King 
686*96f60e37SRussell King 	/*
687*96f60e37SRussell King 	 * Hold the old framebuffer for the work - DRM appears to drop our
688*96f60e37SRussell King 	 * reference to the old framebuffer in drm_mode_page_flip_ioctl().
689*96f60e37SRussell King 	 */
690*96f60e37SRussell King 	drm_framebuffer_reference(work->old_fb);
691*96f60e37SRussell King 
692*96f60e37SRussell King 	ret = armada_drm_crtc_queue_frame_work(dcrtc, work);
693*96f60e37SRussell King 	if (ret) {
694*96f60e37SRussell King 		/*
695*96f60e37SRussell King 		 * Undo our reference above; DRM does not drop the reference
696*96f60e37SRussell King 		 * to this object on error, so that's okay.
697*96f60e37SRussell King 		 */
698*96f60e37SRussell King 		drm_framebuffer_unreference(work->old_fb);
699*96f60e37SRussell King 		kfree(work);
700*96f60e37SRussell King 		return ret;
701*96f60e37SRussell King 	}
702*96f60e37SRussell King 
703*96f60e37SRussell King 	/*
704*96f60e37SRussell King 	 * Don't take a reference on the new framebuffer;
705*96f60e37SRussell King 	 * drm_mode_page_flip_ioctl() has already grabbed a reference and
706*96f60e37SRussell King 	 * will _not_ drop that reference on successful return from this
707*96f60e37SRussell King 	 * function.  Simply mark this new framebuffer as the current one.
708*96f60e37SRussell King 	 */
709*96f60e37SRussell King 	dcrtc->crtc.fb = fb;
710*96f60e37SRussell King 
711*96f60e37SRussell King 	/*
712*96f60e37SRussell King 	 * Finally, if the display is blanked, we won't receive an
713*96f60e37SRussell King 	 * interrupt, so complete it now.
714*96f60e37SRussell King 	 */
715*96f60e37SRussell King 	if (dpms_blanked(dcrtc->dpms)) {
716*96f60e37SRussell King 		spin_lock_irqsave(&dev->event_lock, flags);
717*96f60e37SRussell King 		if (dcrtc->frame_work)
718*96f60e37SRussell King 			armada_drm_crtc_complete_frame_work(dcrtc);
719*96f60e37SRussell King 		spin_unlock_irqrestore(&dev->event_lock, flags);
720*96f60e37SRussell King 	}
721*96f60e37SRussell King 
722*96f60e37SRussell King 	return 0;
723*96f60e37SRussell King }
724*96f60e37SRussell King 
725*96f60e37SRussell King static int
726*96f60e37SRussell King armada_drm_crtc_set_property(struct drm_crtc *crtc,
727*96f60e37SRussell King 	struct drm_property *property, uint64_t val)
728*96f60e37SRussell King {
729*96f60e37SRussell King 	struct armada_private *priv = crtc->dev->dev_private;
730*96f60e37SRussell King 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
731*96f60e37SRussell King 	bool update_csc = false;
732*96f60e37SRussell King 
733*96f60e37SRussell King 	if (property == priv->csc_yuv_prop) {
734*96f60e37SRussell King 		dcrtc->csc_yuv_mode = val;
735*96f60e37SRussell King 		update_csc = true;
736*96f60e37SRussell King 	} else if (property == priv->csc_rgb_prop) {
737*96f60e37SRussell King 		dcrtc->csc_rgb_mode = val;
738*96f60e37SRussell King 		update_csc = true;
739*96f60e37SRussell King 	}
740*96f60e37SRussell King 
741*96f60e37SRussell King 	if (update_csc) {
742*96f60e37SRussell King 		uint32_t val;
743*96f60e37SRussell King 
744*96f60e37SRussell King 		val = dcrtc->spu_iopad_ctrl |
745*96f60e37SRussell King 		      armada_drm_crtc_calculate_csc(dcrtc);
746*96f60e37SRussell King 		writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL);
747*96f60e37SRussell King 	}
748*96f60e37SRussell King 
749*96f60e37SRussell King 	return 0;
750*96f60e37SRussell King }
751*96f60e37SRussell King 
752*96f60e37SRussell King static struct drm_crtc_funcs armada_crtc_funcs = {
753*96f60e37SRussell King 	.destroy	= armada_drm_crtc_destroy,
754*96f60e37SRussell King 	.set_config	= drm_crtc_helper_set_config,
755*96f60e37SRussell King 	.page_flip	= armada_drm_crtc_page_flip,
756*96f60e37SRussell King 	.set_property	= armada_drm_crtc_set_property,
757*96f60e37SRussell King };
758*96f60e37SRussell King 
759*96f60e37SRussell King static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = {
760*96f60e37SRussell King 	{ CSC_AUTO,        "Auto" },
761*96f60e37SRussell King 	{ CSC_YUV_CCIR601, "CCIR601" },
762*96f60e37SRussell King 	{ CSC_YUV_CCIR709, "CCIR709" },
763*96f60e37SRussell King };
764*96f60e37SRussell King 
765*96f60e37SRussell King static struct drm_prop_enum_list armada_drm_csc_rgb_enum_list[] = {
766*96f60e37SRussell King 	{ CSC_AUTO,         "Auto" },
767*96f60e37SRussell King 	{ CSC_RGB_COMPUTER, "Computer system" },
768*96f60e37SRussell King 	{ CSC_RGB_STUDIO,   "Studio" },
769*96f60e37SRussell King };
770*96f60e37SRussell King 
771*96f60e37SRussell King static int armada_drm_crtc_create_properties(struct drm_device *dev)
772*96f60e37SRussell King {
773*96f60e37SRussell King 	struct armada_private *priv = dev->dev_private;
774*96f60e37SRussell King 
775*96f60e37SRussell King 	if (priv->csc_yuv_prop)
776*96f60e37SRussell King 		return 0;
777*96f60e37SRussell King 
778*96f60e37SRussell King 	priv->csc_yuv_prop = drm_property_create_enum(dev, 0,
779*96f60e37SRussell King 				"CSC_YUV", armada_drm_csc_yuv_enum_list,
780*96f60e37SRussell King 				ARRAY_SIZE(armada_drm_csc_yuv_enum_list));
781*96f60e37SRussell King 	priv->csc_rgb_prop = drm_property_create_enum(dev, 0,
782*96f60e37SRussell King 				"CSC_RGB", armada_drm_csc_rgb_enum_list,
783*96f60e37SRussell King 				ARRAY_SIZE(armada_drm_csc_rgb_enum_list));
784*96f60e37SRussell King 
785*96f60e37SRussell King 	if (!priv->csc_yuv_prop || !priv->csc_rgb_prop)
786*96f60e37SRussell King 		return -ENOMEM;
787*96f60e37SRussell King 
788*96f60e37SRussell King 	return 0;
789*96f60e37SRussell King }
790*96f60e37SRussell King 
791*96f60e37SRussell King int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
792*96f60e37SRussell King 	struct resource *res)
793*96f60e37SRussell King {
794*96f60e37SRussell King 	struct armada_private *priv = dev->dev_private;
795*96f60e37SRussell King 	struct armada_crtc *dcrtc;
796*96f60e37SRussell King 	void __iomem *base;
797*96f60e37SRussell King 	int ret;
798*96f60e37SRussell King 
799*96f60e37SRussell King 	ret = armada_drm_crtc_create_properties(dev);
800*96f60e37SRussell King 	if (ret)
801*96f60e37SRussell King 		return ret;
802*96f60e37SRussell King 
803*96f60e37SRussell King 	base = devm_request_and_ioremap(dev->dev, res);
804*96f60e37SRussell King 	if (!base) {
805*96f60e37SRussell King 		DRM_ERROR("failed to ioremap register\n");
806*96f60e37SRussell King 		return -ENOMEM;
807*96f60e37SRussell King 	}
808*96f60e37SRussell King 
809*96f60e37SRussell King 	dcrtc = kzalloc(sizeof(*dcrtc), GFP_KERNEL);
810*96f60e37SRussell King 	if (!dcrtc) {
811*96f60e37SRussell King 		DRM_ERROR("failed to allocate Armada crtc\n");
812*96f60e37SRussell King 		return -ENOMEM;
813*96f60e37SRussell King 	}
814*96f60e37SRussell King 
815*96f60e37SRussell King 	dcrtc->base = base;
816*96f60e37SRussell King 	dcrtc->num = num;
817*96f60e37SRussell King 	dcrtc->clk = ERR_PTR(-EINVAL);
818*96f60e37SRussell King 	dcrtc->csc_yuv_mode = CSC_AUTO;
819*96f60e37SRussell King 	dcrtc->csc_rgb_mode = CSC_AUTO;
820*96f60e37SRussell King 	dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;
821*96f60e37SRussell King 	dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
822*96f60e37SRussell King 	spin_lock_init(&dcrtc->irq_lock);
823*96f60e37SRussell King 	dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR;
824*96f60e37SRussell King 	INIT_LIST_HEAD(&dcrtc->vbl_list);
825*96f60e37SRussell King 	init_waitqueue_head(&dcrtc->frame_wait);
826*96f60e37SRussell King 
827*96f60e37SRussell King 	/* Initialize some registers which we don't otherwise set */
828*96f60e37SRussell King 	writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV);
829*96f60e37SRussell King 	writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_BLANKCOLOR);
830*96f60e37SRussell King 	writel_relaxed(dcrtc->spu_iopad_ctrl,
831*96f60e37SRussell King 		       dcrtc->base + LCD_SPU_IOPAD_CONTROL);
832*96f60e37SRussell King 	writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_SRAM_PARA0);
833*96f60e37SRussell King 	writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
834*96f60e37SRussell King 		       CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
835*96f60e37SRussell King 		       CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
836*96f60e37SRussell King 	writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1);
837*96f60e37SRussell King 	writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN);
838*96f60e37SRussell King 
839*96f60e37SRussell King 	if (priv->variant->crtc_init) {
840*96f60e37SRussell King 		ret = priv->variant->crtc_init(dcrtc);
841*96f60e37SRussell King 		if (ret) {
842*96f60e37SRussell King 			kfree(dcrtc);
843*96f60e37SRussell King 			return ret;
844*96f60e37SRussell King 		}
845*96f60e37SRussell King 	}
846*96f60e37SRussell King 
847*96f60e37SRussell King 	/* Ensure AXI pipeline is enabled */
848*96f60e37SRussell King 	armada_updatel(CFG_ARBFAST_ENA, 0, dcrtc->base + LCD_SPU_DMA_CTRL0);
849*96f60e37SRussell King 
850*96f60e37SRussell King 	priv->dcrtc[dcrtc->num] = dcrtc;
851*96f60e37SRussell King 
852*96f60e37SRussell King 	drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs);
853*96f60e37SRussell King 	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
854*96f60e37SRussell King 
855*96f60e37SRussell King 	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
856*96f60e37SRussell King 				   dcrtc->csc_yuv_mode);
857*96f60e37SRussell King 	drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop,
858*96f60e37SRussell King 				   dcrtc->csc_rgb_mode);
859*96f60e37SRussell King 
860*96f60e37SRussell King 	return armada_overlay_plane_create(dev, 1 << dcrtc->num);
861*96f60e37SRussell King }
862