xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/pl111/pl111_display.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Parts of this file were based on sources as follows:
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (c) 2006-2008 Intel Corporation
8*4882a593Smuzhiyun  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
9*4882a593Smuzhiyun  * Copyright (C) 2011 Texas Instruments
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/clk.h>
13*4882a593Smuzhiyun #include <linux/delay.h>
14*4882a593Smuzhiyun #include <linux/version.h>
15*4882a593Smuzhiyun #include <linux/dma-buf.h>
16*4882a593Smuzhiyun #include <linux/of_graph.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <drm/drm_fb_cma_helper.h>
19*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
20*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
21*4882a593Smuzhiyun #include <drm/drm_gem_framebuffer_helper.h>
22*4882a593Smuzhiyun #include <drm/drm_vblank.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "pl111_drm.h"
25*4882a593Smuzhiyun 
pl111_irq(int irq,void * data)26*4882a593Smuzhiyun irqreturn_t pl111_irq(int irq, void *data)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = data;
29*4882a593Smuzhiyun 	u32 irq_stat;
30*4882a593Smuzhiyun 	irqreturn_t status = IRQ_NONE;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	irq_stat = readl(priv->regs + CLCD_PL111_MIS);
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	if (!irq_stat)
35*4882a593Smuzhiyun 		return IRQ_NONE;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (irq_stat & CLCD_IRQ_NEXTBASE_UPDATE) {
38*4882a593Smuzhiyun 		drm_crtc_handle_vblank(&priv->pipe.crtc);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 		status = IRQ_HANDLED;
41*4882a593Smuzhiyun 	}
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	/* Clear the interrupt once done */
44*4882a593Smuzhiyun 	writel(irq_stat, priv->regs + CLCD_PL111_ICR);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	return status;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static enum drm_mode_status
pl111_mode_valid(struct drm_simple_display_pipe * pipe,const struct drm_display_mode * mode)50*4882a593Smuzhiyun pl111_mode_valid(struct drm_simple_display_pipe *pipe,
51*4882a593Smuzhiyun 		 const struct drm_display_mode *mode)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	struct drm_device *drm = pipe->crtc.dev;
54*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
55*4882a593Smuzhiyun 	u32 cpp = priv->variant->fb_bpp / 8;
56*4882a593Smuzhiyun 	u64 bw;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/*
59*4882a593Smuzhiyun 	 * We use the pixelclock to also account for interlaced modes, the
60*4882a593Smuzhiyun 	 * resulting bandwidth is in bytes per second.
61*4882a593Smuzhiyun 	 */
62*4882a593Smuzhiyun 	bw = mode->clock * 1000ULL; /* In Hz */
63*4882a593Smuzhiyun 	bw = bw * mode->hdisplay * mode->vdisplay * cpp;
64*4882a593Smuzhiyun 	bw = div_u64(bw, mode->htotal * mode->vtotal);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/*
67*4882a593Smuzhiyun 	 * If no bandwidth constraints, anything goes, else
68*4882a593Smuzhiyun 	 * check if we are too fast.
69*4882a593Smuzhiyun 	 */
70*4882a593Smuzhiyun 	if (priv->memory_bw && (bw > priv->memory_bw)) {
71*4882a593Smuzhiyun 		DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu too fast\n",
72*4882a593Smuzhiyun 			      mode->hdisplay, mode->vdisplay,
73*4882a593Smuzhiyun 			      mode->clock * 1000, cpp, bw);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 		return MODE_BAD;
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun 	DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu bytes/s OK\n",
78*4882a593Smuzhiyun 		      mode->hdisplay, mode->vdisplay,
79*4882a593Smuzhiyun 		      mode->clock * 1000, cpp, bw);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return MODE_OK;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
pl111_display_check(struct drm_simple_display_pipe * pipe,struct drm_plane_state * pstate,struct drm_crtc_state * cstate)84*4882a593Smuzhiyun static int pl111_display_check(struct drm_simple_display_pipe *pipe,
85*4882a593Smuzhiyun 			       struct drm_plane_state *pstate,
86*4882a593Smuzhiyun 			       struct drm_crtc_state *cstate)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	const struct drm_display_mode *mode = &cstate->mode;
89*4882a593Smuzhiyun 	struct drm_framebuffer *old_fb = pipe->plane.state->fb;
90*4882a593Smuzhiyun 	struct drm_framebuffer *fb = pstate->fb;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (mode->hdisplay % 16)
93*4882a593Smuzhiyun 		return -EINVAL;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (fb) {
96*4882a593Smuzhiyun 		u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 		/* FB base address must be dword aligned. */
99*4882a593Smuzhiyun 		if (offset & 3)
100*4882a593Smuzhiyun 			return -EINVAL;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 		/* There's no pitch register -- the mode's hdisplay
103*4882a593Smuzhiyun 		 * controls it.
104*4882a593Smuzhiyun 		 */
105*4882a593Smuzhiyun 		if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0])
106*4882a593Smuzhiyun 			return -EINVAL;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 		/* We can't change the FB format in a flicker-free
109*4882a593Smuzhiyun 		 * manner (and only update it during CRTC enable).
110*4882a593Smuzhiyun 		 */
111*4882a593Smuzhiyun 		if (old_fb && old_fb->format != fb->format)
112*4882a593Smuzhiyun 			cstate->mode_changed = true;
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
pl111_display_enable(struct drm_simple_display_pipe * pipe,struct drm_crtc_state * cstate,struct drm_plane_state * plane_state)118*4882a593Smuzhiyun static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
119*4882a593Smuzhiyun 				 struct drm_crtc_state *cstate,
120*4882a593Smuzhiyun 				 struct drm_plane_state *plane_state)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct drm_crtc *crtc = &pipe->crtc;
123*4882a593Smuzhiyun 	struct drm_plane *plane = &pipe->plane;
124*4882a593Smuzhiyun 	struct drm_device *drm = crtc->dev;
125*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
126*4882a593Smuzhiyun 	const struct drm_display_mode *mode = &cstate->mode;
127*4882a593Smuzhiyun 	struct drm_framebuffer *fb = plane->state->fb;
128*4882a593Smuzhiyun 	struct drm_connector *connector = priv->connector;
129*4882a593Smuzhiyun 	struct drm_bridge *bridge = priv->bridge;
130*4882a593Smuzhiyun 	bool grayscale = false;
131*4882a593Smuzhiyun 	u32 cntl;
132*4882a593Smuzhiyun 	u32 ppl, hsw, hfp, hbp;
133*4882a593Smuzhiyun 	u32 lpp, vsw, vfp, vbp;
134*4882a593Smuzhiyun 	u32 cpl, tim2;
135*4882a593Smuzhiyun 	int ret;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	ret = clk_set_rate(priv->clk, mode->clock * 1000);
138*4882a593Smuzhiyun 	if (ret) {
139*4882a593Smuzhiyun 		dev_err(drm->dev,
140*4882a593Smuzhiyun 			"Failed to set pixel clock rate to %d: %d\n",
141*4882a593Smuzhiyun 			mode->clock * 1000, ret);
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	clk_prepare_enable(priv->clk);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	ppl = (mode->hdisplay / 16) - 1;
147*4882a593Smuzhiyun 	hsw = mode->hsync_end - mode->hsync_start - 1;
148*4882a593Smuzhiyun 	hfp = mode->hsync_start - mode->hdisplay - 1;
149*4882a593Smuzhiyun 	hbp = mode->htotal - mode->hsync_end - 1;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	lpp = mode->vdisplay - 1;
152*4882a593Smuzhiyun 	vsw = mode->vsync_end - mode->vsync_start - 1;
153*4882a593Smuzhiyun 	vfp = mode->vsync_start - mode->vdisplay;
154*4882a593Smuzhiyun 	vbp = mode->vtotal - mode->vsync_end;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	cpl = mode->hdisplay - 1;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	writel((ppl << 2) |
159*4882a593Smuzhiyun 	       (hsw << 8) |
160*4882a593Smuzhiyun 	       (hfp << 16) |
161*4882a593Smuzhiyun 	       (hbp << 24),
162*4882a593Smuzhiyun 	       priv->regs + CLCD_TIM0);
163*4882a593Smuzhiyun 	writel(lpp |
164*4882a593Smuzhiyun 	       (vsw << 10) |
165*4882a593Smuzhiyun 	       (vfp << 16) |
166*4882a593Smuzhiyun 	       (vbp << 24),
167*4882a593Smuzhiyun 	       priv->regs + CLCD_TIM1);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	spin_lock(&priv->tim2_lock);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	tim2 = readl(priv->regs + CLCD_TIM2);
172*4882a593Smuzhiyun 	tim2 &= (TIM2_BCD | TIM2_PCD_LO_MASK | TIM2_PCD_HI_MASK);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (priv->variant->broken_clockdivider)
175*4882a593Smuzhiyun 		tim2 |= TIM2_BCD;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
178*4882a593Smuzhiyun 		tim2 |= TIM2_IHS;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
181*4882a593Smuzhiyun 		tim2 |= TIM2_IVS;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (connector) {
184*4882a593Smuzhiyun 		if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW)
185*4882a593Smuzhiyun 			tim2 |= TIM2_IOE;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 		if (connector->display_info.bus_flags &
188*4882a593Smuzhiyun 		    DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
189*4882a593Smuzhiyun 			tim2 |= TIM2_IPC;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		if (connector->display_info.num_bus_formats == 1 &&
192*4882a593Smuzhiyun 		    connector->display_info.bus_formats[0] ==
193*4882a593Smuzhiyun 		    MEDIA_BUS_FMT_Y8_1X8)
194*4882a593Smuzhiyun 			grayscale = true;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 		/*
197*4882a593Smuzhiyun 		 * The AC pin bias frequency is set to max count when using
198*4882a593Smuzhiyun 		 * grayscale so at least once in a while we will reverse
199*4882a593Smuzhiyun 		 * polarity and get rid of any DC built up that could
200*4882a593Smuzhiyun 		 * damage the display.
201*4882a593Smuzhiyun 		 */
202*4882a593Smuzhiyun 		if (grayscale)
203*4882a593Smuzhiyun 			tim2 |= TIM2_ACB_MASK;
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	if (bridge) {
207*4882a593Smuzhiyun 		const struct drm_bridge_timings *btimings = bridge->timings;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		/*
210*4882a593Smuzhiyun 		 * Here is when things get really fun. Sometimes the bridge
211*4882a593Smuzhiyun 		 * timings are such that the signal out from PL11x is not
212*4882a593Smuzhiyun 		 * stable before the receiving bridge (such as a dumb VGA DAC
213*4882a593Smuzhiyun 		 * or similar) samples it. If that happens, we compensate by
214*4882a593Smuzhiyun 		 * the only method we have: output the data on the opposite
215*4882a593Smuzhiyun 		 * edge of the clock so it is for sure stable when it gets
216*4882a593Smuzhiyun 		 * sampled.
217*4882a593Smuzhiyun 		 *
218*4882a593Smuzhiyun 		 * The PL111 manual does not contain proper timining diagrams
219*4882a593Smuzhiyun 		 * or data for these details, but we know from experiments
220*4882a593Smuzhiyun 		 * that the setup time is more than 3000 picoseconds (3 ns).
221*4882a593Smuzhiyun 		 * If we have a bridge that requires the signal to be stable
222*4882a593Smuzhiyun 		 * earlier than 3000 ps before the clock pulse, we have to
223*4882a593Smuzhiyun 		 * output the data on the opposite edge to avoid flicker.
224*4882a593Smuzhiyun 		 */
225*4882a593Smuzhiyun 		if (btimings && btimings->setup_time_ps >= 3000)
226*4882a593Smuzhiyun 			tim2 ^= TIM2_IPC;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	tim2 |= cpl << 16;
230*4882a593Smuzhiyun 	writel(tim2, priv->regs + CLCD_TIM2);
231*4882a593Smuzhiyun 	spin_unlock(&priv->tim2_lock);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	writel(0, priv->regs + CLCD_TIM3);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/*
236*4882a593Smuzhiyun 	 * Detect grayscale bus format. We do not support a grayscale mode
237*4882a593Smuzhiyun 	 * toward userspace, instead we expose an RGB24 buffer and then the
238*4882a593Smuzhiyun 	 * hardware will activate its grayscaler to convert to the grayscale
239*4882a593Smuzhiyun 	 * format.
240*4882a593Smuzhiyun 	 */
241*4882a593Smuzhiyun 	if (grayscale)
242*4882a593Smuzhiyun 		cntl = CNTL_LCDEN | CNTL_LCDMONO8;
243*4882a593Smuzhiyun 	else
244*4882a593Smuzhiyun 		/* Else we assume TFT display */
245*4882a593Smuzhiyun 		cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDVCOMP(1);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* On the ST Micro variant, assume all 24 bits are connected */
248*4882a593Smuzhiyun 	if (priv->variant->st_bitmux_control)
249*4882a593Smuzhiyun 		cntl |= CNTL_ST_CDWID_24;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/*
252*4882a593Smuzhiyun 	 * Note that the the ARM hardware's format reader takes 'r' from
253*4882a593Smuzhiyun 	 * the low bit, while DRM formats list channels from high bit
254*4882a593Smuzhiyun 	 * to low bit as you read left to right. The ST Micro version of
255*4882a593Smuzhiyun 	 * the PL110 (LCDC) however uses the standard DRM format.
256*4882a593Smuzhiyun 	 */
257*4882a593Smuzhiyun 	switch (fb->format->format) {
258*4882a593Smuzhiyun 	case DRM_FORMAT_BGR888:
259*4882a593Smuzhiyun 		/* Only supported on the ST Micro variant */
260*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
261*4882a593Smuzhiyun 			cntl |= CNTL_ST_LCDBPP24_PACKED | CNTL_BGR;
262*4882a593Smuzhiyun 		break;
263*4882a593Smuzhiyun 	case DRM_FORMAT_RGB888:
264*4882a593Smuzhiyun 		/* Only supported on the ST Micro variant */
265*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
266*4882a593Smuzhiyun 			cntl |= CNTL_ST_LCDBPP24_PACKED;
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 	case DRM_FORMAT_ABGR8888:
269*4882a593Smuzhiyun 	case DRM_FORMAT_XBGR8888:
270*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
271*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP24 | CNTL_BGR;
272*4882a593Smuzhiyun 		else
273*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP24;
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB8888:
276*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB8888:
277*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
278*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP24;
279*4882a593Smuzhiyun 		else
280*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP24 | CNTL_BGR;
281*4882a593Smuzhiyun 		break;
282*4882a593Smuzhiyun 	case DRM_FORMAT_BGR565:
283*4882a593Smuzhiyun 		if (priv->variant->is_pl110)
284*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP16;
285*4882a593Smuzhiyun 		else if (priv->variant->st_bitmux_control)
286*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP16 | CNTL_ST_1XBPP_565 | CNTL_BGR;
287*4882a593Smuzhiyun 		else
288*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP16_565;
289*4882a593Smuzhiyun 		break;
290*4882a593Smuzhiyun 	case DRM_FORMAT_RGB565:
291*4882a593Smuzhiyun 		if (priv->variant->is_pl110)
292*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP16 | CNTL_BGR;
293*4882a593Smuzhiyun 		else if (priv->variant->st_bitmux_control)
294*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP16 | CNTL_ST_1XBPP_565;
295*4882a593Smuzhiyun 		else
296*4882a593Smuzhiyun 			cntl |= CNTL_LCDBPP16_565 | CNTL_BGR;
297*4882a593Smuzhiyun 		break;
298*4882a593Smuzhiyun 	case DRM_FORMAT_ABGR1555:
299*4882a593Smuzhiyun 	case DRM_FORMAT_XBGR1555:
300*4882a593Smuzhiyun 		cntl |= CNTL_LCDBPP16;
301*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
302*4882a593Smuzhiyun 			cntl |= CNTL_ST_1XBPP_5551 | CNTL_BGR;
303*4882a593Smuzhiyun 		break;
304*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB1555:
305*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB1555:
306*4882a593Smuzhiyun 		cntl |= CNTL_LCDBPP16;
307*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
308*4882a593Smuzhiyun 			cntl |= CNTL_ST_1XBPP_5551;
309*4882a593Smuzhiyun 		else
310*4882a593Smuzhiyun 			cntl |= CNTL_BGR;
311*4882a593Smuzhiyun 		break;
312*4882a593Smuzhiyun 	case DRM_FORMAT_ABGR4444:
313*4882a593Smuzhiyun 	case DRM_FORMAT_XBGR4444:
314*4882a593Smuzhiyun 		cntl |= CNTL_LCDBPP16_444;
315*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
316*4882a593Smuzhiyun 			cntl |= CNTL_ST_1XBPP_444 | CNTL_BGR;
317*4882a593Smuzhiyun 		break;
318*4882a593Smuzhiyun 	case DRM_FORMAT_ARGB4444:
319*4882a593Smuzhiyun 	case DRM_FORMAT_XRGB4444:
320*4882a593Smuzhiyun 		cntl |= CNTL_LCDBPP16_444;
321*4882a593Smuzhiyun 		if (priv->variant->st_bitmux_control)
322*4882a593Smuzhiyun 			cntl |= CNTL_ST_1XBPP_444;
323*4882a593Smuzhiyun 		else
324*4882a593Smuzhiyun 			cntl |= CNTL_BGR;
325*4882a593Smuzhiyun 		break;
326*4882a593Smuzhiyun 	default:
327*4882a593Smuzhiyun 		WARN_ONCE(true, "Unknown FB format 0x%08x\n",
328*4882a593Smuzhiyun 			  fb->format->format);
329*4882a593Smuzhiyun 		break;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* The PL110 in Integrator/Versatile does the BGR routing externally */
333*4882a593Smuzhiyun 	if (priv->variant->external_bgr)
334*4882a593Smuzhiyun 		cntl &= ~CNTL_BGR;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* Power sequence: first enable and chill */
337*4882a593Smuzhiyun 	writel(cntl, priv->regs + priv->ctrl);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/*
340*4882a593Smuzhiyun 	 * We expect this delay to stabilize the contrast
341*4882a593Smuzhiyun 	 * voltage Vee as stipulated by the manual
342*4882a593Smuzhiyun 	 */
343*4882a593Smuzhiyun 	msleep(20);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	if (priv->variant_display_enable)
346*4882a593Smuzhiyun 		priv->variant_display_enable(drm, fb->format->format);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Power Up */
349*4882a593Smuzhiyun 	cntl |= CNTL_LCDPWR;
350*4882a593Smuzhiyun 	writel(cntl, priv->regs + priv->ctrl);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	if (!priv->variant->broken_vblank)
353*4882a593Smuzhiyun 		drm_crtc_vblank_on(crtc);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
pl111_display_disable(struct drm_simple_display_pipe * pipe)356*4882a593Smuzhiyun void pl111_display_disable(struct drm_simple_display_pipe *pipe)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct drm_crtc *crtc = &pipe->crtc;
359*4882a593Smuzhiyun 	struct drm_device *drm = crtc->dev;
360*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
361*4882a593Smuzhiyun 	u32 cntl;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (!priv->variant->broken_vblank)
364*4882a593Smuzhiyun 		drm_crtc_vblank_off(crtc);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* Power Down */
367*4882a593Smuzhiyun 	cntl = readl(priv->regs + priv->ctrl);
368*4882a593Smuzhiyun 	if (cntl & CNTL_LCDPWR) {
369*4882a593Smuzhiyun 		cntl &= ~CNTL_LCDPWR;
370*4882a593Smuzhiyun 		writel(cntl, priv->regs + priv->ctrl);
371*4882a593Smuzhiyun 	}
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	/*
374*4882a593Smuzhiyun 	 * We expect this delay to stabilize the contrast voltage Vee as
375*4882a593Smuzhiyun 	 * stipulated by the manual
376*4882a593Smuzhiyun 	 */
377*4882a593Smuzhiyun 	msleep(20);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (priv->variant_display_disable)
380*4882a593Smuzhiyun 		priv->variant_display_disable(drm);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	/* Disable */
383*4882a593Smuzhiyun 	writel(0, priv->regs + priv->ctrl);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	clk_disable_unprepare(priv->clk);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
pl111_display_update(struct drm_simple_display_pipe * pipe,struct drm_plane_state * old_pstate)388*4882a593Smuzhiyun static void pl111_display_update(struct drm_simple_display_pipe *pipe,
389*4882a593Smuzhiyun 				 struct drm_plane_state *old_pstate)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun 	struct drm_crtc *crtc = &pipe->crtc;
392*4882a593Smuzhiyun 	struct drm_device *drm = crtc->dev;
393*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
394*4882a593Smuzhiyun 	struct drm_pending_vblank_event *event = crtc->state->event;
395*4882a593Smuzhiyun 	struct drm_plane *plane = &pipe->plane;
396*4882a593Smuzhiyun 	struct drm_plane_state *pstate = plane->state;
397*4882a593Smuzhiyun 	struct drm_framebuffer *fb = pstate->fb;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	if (fb) {
400*4882a593Smuzhiyun 		u32 addr = drm_fb_cma_get_gem_addr(fb, pstate, 0);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 		writel(addr, priv->regs + CLCD_UBAS);
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	if (event) {
406*4882a593Smuzhiyun 		crtc->state->event = NULL;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 		spin_lock_irq(&crtc->dev->event_lock);
409*4882a593Smuzhiyun 		if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
410*4882a593Smuzhiyun 			drm_crtc_arm_vblank_event(crtc, event);
411*4882a593Smuzhiyun 		else
412*4882a593Smuzhiyun 			drm_crtc_send_vblank_event(crtc, event);
413*4882a593Smuzhiyun 		spin_unlock_irq(&crtc->dev->event_lock);
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
pl111_display_enable_vblank(struct drm_simple_display_pipe * pipe)417*4882a593Smuzhiyun static int pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct drm_crtc *crtc = &pipe->crtc;
420*4882a593Smuzhiyun 	struct drm_device *drm = crtc->dev;
421*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + priv->ienb);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	return 0;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
pl111_display_disable_vblank(struct drm_simple_display_pipe * pipe)428*4882a593Smuzhiyun static void pl111_display_disable_vblank(struct drm_simple_display_pipe *pipe)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	struct drm_crtc *crtc = &pipe->crtc;
431*4882a593Smuzhiyun 	struct drm_device *drm = crtc->dev;
432*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	writel(0, priv->regs + priv->ienb);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun static struct drm_simple_display_pipe_funcs pl111_display_funcs = {
438*4882a593Smuzhiyun 	.mode_valid = pl111_mode_valid,
439*4882a593Smuzhiyun 	.check = pl111_display_check,
440*4882a593Smuzhiyun 	.enable = pl111_display_enable,
441*4882a593Smuzhiyun 	.disable = pl111_display_disable,
442*4882a593Smuzhiyun 	.update = pl111_display_update,
443*4882a593Smuzhiyun 	.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
444*4882a593Smuzhiyun };
445*4882a593Smuzhiyun 
pl111_clk_div_choose_div(struct clk_hw * hw,unsigned long rate,unsigned long * prate,bool set_parent)446*4882a593Smuzhiyun static int pl111_clk_div_choose_div(struct clk_hw *hw, unsigned long rate,
447*4882a593Smuzhiyun 				    unsigned long *prate, bool set_parent)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	int best_div = 1, div;
450*4882a593Smuzhiyun 	struct clk_hw *parent = clk_hw_get_parent(hw);
451*4882a593Smuzhiyun 	unsigned long best_prate = 0;
452*4882a593Smuzhiyun 	unsigned long best_diff = ~0ul;
453*4882a593Smuzhiyun 	int max_div = (1 << (TIM2_PCD_LO_BITS + TIM2_PCD_HI_BITS)) - 1;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	for (div = 1; div < max_div; div++) {
456*4882a593Smuzhiyun 		unsigned long this_prate, div_rate, diff;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 		if (set_parent)
459*4882a593Smuzhiyun 			this_prate = clk_hw_round_rate(parent, rate * div);
460*4882a593Smuzhiyun 		else
461*4882a593Smuzhiyun 			this_prate = *prate;
462*4882a593Smuzhiyun 		div_rate = DIV_ROUND_UP_ULL(this_prate, div);
463*4882a593Smuzhiyun 		diff = abs(rate - div_rate);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 		if (diff < best_diff) {
466*4882a593Smuzhiyun 			best_div = div;
467*4882a593Smuzhiyun 			best_diff = diff;
468*4882a593Smuzhiyun 			best_prate = this_prate;
469*4882a593Smuzhiyun 		}
470*4882a593Smuzhiyun 	}
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	*prate = best_prate;
473*4882a593Smuzhiyun 	return best_div;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
pl111_clk_div_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)476*4882a593Smuzhiyun static long pl111_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
477*4882a593Smuzhiyun 				     unsigned long *prate)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	int div = pl111_clk_div_choose_div(hw, rate, prate, true);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	return DIV_ROUND_UP_ULL(*prate, div);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
pl111_clk_div_recalc_rate(struct clk_hw * hw,unsigned long prate)484*4882a593Smuzhiyun static unsigned long pl111_clk_div_recalc_rate(struct clk_hw *hw,
485*4882a593Smuzhiyun 					       unsigned long prate)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv =
488*4882a593Smuzhiyun 		container_of(hw, struct pl111_drm_dev_private, clk_div);
489*4882a593Smuzhiyun 	u32 tim2 = readl(priv->regs + CLCD_TIM2);
490*4882a593Smuzhiyun 	int div;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if (tim2 & TIM2_BCD)
493*4882a593Smuzhiyun 		return prate;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	div = tim2 & TIM2_PCD_LO_MASK;
496*4882a593Smuzhiyun 	div |= (tim2 & TIM2_PCD_HI_MASK) >>
497*4882a593Smuzhiyun 		(TIM2_PCD_HI_SHIFT - TIM2_PCD_LO_BITS);
498*4882a593Smuzhiyun 	div += 2;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	return DIV_ROUND_UP_ULL(prate, div);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
pl111_clk_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long prate)503*4882a593Smuzhiyun static int pl111_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
504*4882a593Smuzhiyun 				  unsigned long prate)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv =
507*4882a593Smuzhiyun 		container_of(hw, struct pl111_drm_dev_private, clk_div);
508*4882a593Smuzhiyun 	int div = pl111_clk_div_choose_div(hw, rate, &prate, false);
509*4882a593Smuzhiyun 	u32 tim2;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	spin_lock(&priv->tim2_lock);
512*4882a593Smuzhiyun 	tim2 = readl(priv->regs + CLCD_TIM2);
513*4882a593Smuzhiyun 	tim2 &= ~(TIM2_BCD | TIM2_PCD_LO_MASK | TIM2_PCD_HI_MASK);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	if (div == 1) {
516*4882a593Smuzhiyun 		tim2 |= TIM2_BCD;
517*4882a593Smuzhiyun 	} else {
518*4882a593Smuzhiyun 		div -= 2;
519*4882a593Smuzhiyun 		tim2 |= div & TIM2_PCD_LO_MASK;
520*4882a593Smuzhiyun 		tim2 |= (div >> TIM2_PCD_LO_BITS) << TIM2_PCD_HI_SHIFT;
521*4882a593Smuzhiyun 	}
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	writel(tim2, priv->regs + CLCD_TIM2);
524*4882a593Smuzhiyun 	spin_unlock(&priv->tim2_lock);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun static const struct clk_ops pl111_clk_div_ops = {
530*4882a593Smuzhiyun 	.recalc_rate = pl111_clk_div_recalc_rate,
531*4882a593Smuzhiyun 	.round_rate = pl111_clk_div_round_rate,
532*4882a593Smuzhiyun 	.set_rate = pl111_clk_div_set_rate,
533*4882a593Smuzhiyun };
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun static int
pl111_init_clock_divider(struct drm_device * drm)536*4882a593Smuzhiyun pl111_init_clock_divider(struct drm_device *drm)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
539*4882a593Smuzhiyun 	struct clk *parent = devm_clk_get(drm->dev, "clcdclk");
540*4882a593Smuzhiyun 	struct clk_hw *div = &priv->clk_div;
541*4882a593Smuzhiyun 	const char *parent_name;
542*4882a593Smuzhiyun 	struct clk_init_data init = {
543*4882a593Smuzhiyun 		.name = "pl111_div",
544*4882a593Smuzhiyun 		.ops = &pl111_clk_div_ops,
545*4882a593Smuzhiyun 		.parent_names = &parent_name,
546*4882a593Smuzhiyun 		.num_parents = 1,
547*4882a593Smuzhiyun 		.flags = CLK_SET_RATE_PARENT,
548*4882a593Smuzhiyun 	};
549*4882a593Smuzhiyun 	int ret;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	if (IS_ERR(parent)) {
552*4882a593Smuzhiyun 		dev_err(drm->dev, "CLCD: unable to get clcdclk.\n");
553*4882a593Smuzhiyun 		return PTR_ERR(parent);
554*4882a593Smuzhiyun 	}
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	spin_lock_init(&priv->tim2_lock);
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	/* If the clock divider is broken, use the parent directly */
559*4882a593Smuzhiyun 	if (priv->variant->broken_clockdivider) {
560*4882a593Smuzhiyun 		priv->clk = parent;
561*4882a593Smuzhiyun 		return 0;
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 	parent_name = __clk_get_name(parent);
564*4882a593Smuzhiyun 	div->init = &init;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	ret = devm_clk_hw_register(drm->dev, div);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	priv->clk = div->clk;
569*4882a593Smuzhiyun 	return ret;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun 
pl111_display_init(struct drm_device * drm)572*4882a593Smuzhiyun int pl111_display_init(struct drm_device *drm)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
575*4882a593Smuzhiyun 	int ret;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	ret = pl111_init_clock_divider(drm);
578*4882a593Smuzhiyun 	if (ret)
579*4882a593Smuzhiyun 		return ret;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	if (!priv->variant->broken_vblank) {
582*4882a593Smuzhiyun 		pl111_display_funcs.enable_vblank = pl111_display_enable_vblank;
583*4882a593Smuzhiyun 		pl111_display_funcs.disable_vblank = pl111_display_disable_vblank;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	ret = drm_simple_display_pipe_init(drm, &priv->pipe,
587*4882a593Smuzhiyun 					   &pl111_display_funcs,
588*4882a593Smuzhiyun 					   priv->variant->formats,
589*4882a593Smuzhiyun 					   priv->variant->nformats,
590*4882a593Smuzhiyun 					   NULL,
591*4882a593Smuzhiyun 					   priv->connector);
592*4882a593Smuzhiyun 	if (ret)
593*4882a593Smuzhiyun 		return ret;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	return 0;
596*4882a593Smuzhiyun }
597