xref: /openbmc/linux/drivers/gpu/drm/pl111/pl111_display.c (revision a6ca5ac746d104019e76c29e69c2a1fc6dd2b29f)
1 /*
2  * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
3  *
4  * Parts of this file were based on sources as follows:
5  *
6  * Copyright (c) 2006-2008 Intel Corporation
7  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
8  * Copyright (C) 2011 Texas Instruments
9  *
10  * This program is free software and is provided to you under the terms of the
11  * GNU General Public License version 2 as published by the Free Software
12  * Foundation, and any use by you of this program is subject to the terms of
13  * such GNU licence.
14  *
15  */
16 
17 #include <linux/amba/clcd-regs.h>
18 #include <linux/clk.h>
19 #include <linux/version.h>
20 #include <linux/dma-buf.h>
21 #include <linux/of_graph.h>
22 
23 #include <drm/drmP.h>
24 #include <drm/drm_panel.h>
25 #include <drm/drm_gem_cma_helper.h>
26 #include <drm/drm_fb_cma_helper.h>
27 
28 #include "pl111_drm.h"
29 
30 irqreturn_t pl111_irq(int irq, void *data)
31 {
32 	struct pl111_drm_dev_private *priv = data;
33 	u32 irq_stat;
34 	irqreturn_t status = IRQ_NONE;
35 
36 	irq_stat = readl(priv->regs + CLCD_PL111_MIS);
37 
38 	if (!irq_stat)
39 		return IRQ_NONE;
40 
41 	if (irq_stat & CLCD_IRQ_NEXTBASE_UPDATE) {
42 		drm_crtc_handle_vblank(&priv->pipe.crtc);
43 
44 		status = IRQ_HANDLED;
45 	}
46 
47 	/* Clear the interrupt once done */
48 	writel(irq_stat, priv->regs + CLCD_PL111_ICR);
49 
50 	return status;
51 }
52 
53 static u32 pl111_get_fb_offset(struct drm_plane_state *pstate)
54 {
55 	struct drm_framebuffer *fb = pstate->fb;
56 	struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
57 
58 	return (obj->paddr +
59 		fb->offsets[0] +
60 		fb->format->cpp[0] * pstate->src_x +
61 		fb->pitches[0] * pstate->src_y);
62 }
63 
64 static int pl111_display_check(struct drm_simple_display_pipe *pipe,
65 			       struct drm_plane_state *pstate,
66 			       struct drm_crtc_state *cstate)
67 {
68 	const struct drm_display_mode *mode = &cstate->mode;
69 	struct drm_framebuffer *old_fb = pipe->plane.state->fb;
70 	struct drm_framebuffer *fb = pstate->fb;
71 
72 	if (mode->hdisplay % 16)
73 		return -EINVAL;
74 
75 	if (fb) {
76 		u32 offset = pl111_get_fb_offset(pstate);
77 
78 		/* FB base address must be dword aligned. */
79 		if (offset & 3)
80 			return -EINVAL;
81 
82 		/* There's no pitch register -- the mode's hdisplay
83 		 * controls it.
84 		 */
85 		if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0])
86 			return -EINVAL;
87 
88 		/* We can't change the FB format in a flicker-free
89 		 * manner (and only update it during CRTC enable).
90 		 */
91 		if (old_fb && old_fb->format != fb->format)
92 			cstate->mode_changed = true;
93 	}
94 
95 	return 0;
96 }
97 
98 static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
99 				 struct drm_crtc_state *cstate)
100 {
101 	struct drm_crtc *crtc = &pipe->crtc;
102 	struct drm_plane *plane = &pipe->plane;
103 	struct drm_device *drm = crtc->dev;
104 	struct pl111_drm_dev_private *priv = drm->dev_private;
105 	const struct drm_display_mode *mode = &cstate->mode;
106 	struct drm_framebuffer *fb = plane->state->fb;
107 	struct drm_connector *connector = &priv->connector.connector;
108 	u32 cntl;
109 	u32 ppl, hsw, hfp, hbp;
110 	u32 lpp, vsw, vfp, vbp;
111 	u32 cpl;
112 	int ret;
113 
114 	ret = clk_set_rate(priv->clk, mode->clock * 1000);
115 	if (ret) {
116 		dev_err(drm->dev,
117 			"Failed to set pixel clock rate to %d: %d\n",
118 			mode->clock * 1000, ret);
119 	}
120 
121 	clk_prepare_enable(priv->clk);
122 
123 	ppl = (mode->hdisplay / 16) - 1;
124 	hsw = mode->hsync_end - mode->hsync_start - 1;
125 	hfp = mode->hsync_start - mode->hdisplay - 1;
126 	hbp = mode->htotal - mode->hsync_end - 1;
127 
128 	lpp = mode->vdisplay - 1;
129 	vsw = mode->vsync_end - mode->vsync_start - 1;
130 	vfp = mode->vsync_start - mode->vdisplay;
131 	vbp = mode->vtotal - mode->vsync_end;
132 
133 	cpl = mode->hdisplay - 1;
134 
135 	writel((ppl << 2) |
136 	       (hsw << 8) |
137 	       (hfp << 16) |
138 	       (hbp << 24),
139 	       priv->regs + CLCD_TIM0);
140 	writel(lpp |
141 	       (vsw << 10) |
142 	       (vfp << 16) |
143 	       (vbp << 24),
144 	       priv->regs + CLCD_TIM1);
145 	/* XXX: We currently always use CLCDCLK with no divisor.  We
146 	 * could probably reduce power consumption by using HCLK
147 	 * (apb_pclk) with a divisor when it gets us near our target
148 	 * pixel clock.
149 	 */
150 	writel(((mode->flags & DRM_MODE_FLAG_NHSYNC) ? TIM2_IHS : 0) |
151 	       ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? TIM2_IVS : 0) |
152 	       ((connector->display_info.bus_flags &
153 		 DRM_BUS_FLAG_DE_LOW) ? TIM2_IOE : 0) |
154 	       ((connector->display_info.bus_flags &
155 		 DRM_BUS_FLAG_PIXDATA_NEGEDGE) ? TIM2_IPC : 0) |
156 	       TIM2_BCD |
157 	       (cpl << 16),
158 	       priv->regs + CLCD_TIM2);
159 	writel(0, priv->regs + CLCD_TIM3);
160 
161 	drm_panel_prepare(priv->connector.panel);
162 
163 	/* Enable and Power Up */
164 	cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDPWR | CNTL_LCDVCOMP(1);
165 
166 	/* Note that the the hardware's format reader takes 'r' from
167 	 * the low bit, while DRM formats list channels from high bit
168 	 * to low bit as you read left to right.
169 	 */
170 	switch (fb->format->format) {
171 	case DRM_FORMAT_ABGR8888:
172 	case DRM_FORMAT_XBGR8888:
173 		cntl |= CNTL_LCDBPP24;
174 		break;
175 	case DRM_FORMAT_ARGB8888:
176 	case DRM_FORMAT_XRGB8888:
177 		cntl |= CNTL_LCDBPP24 | CNTL_BGR;
178 		break;
179 	case DRM_FORMAT_BGR565:
180 		cntl |= CNTL_LCDBPP16_565;
181 		break;
182 	case DRM_FORMAT_RGB565:
183 		cntl |= CNTL_LCDBPP16_565 | CNTL_BGR;
184 		break;
185 	case DRM_FORMAT_ABGR1555:
186 	case DRM_FORMAT_XBGR1555:
187 		cntl |= CNTL_LCDBPP16;
188 		break;
189 	case DRM_FORMAT_ARGB1555:
190 	case DRM_FORMAT_XRGB1555:
191 		cntl |= CNTL_LCDBPP16 | CNTL_BGR;
192 		break;
193 	case DRM_FORMAT_ABGR4444:
194 	case DRM_FORMAT_XBGR4444:
195 		cntl |= CNTL_LCDBPP16_444;
196 		break;
197 	case DRM_FORMAT_ARGB4444:
198 	case DRM_FORMAT_XRGB4444:
199 		cntl |= CNTL_LCDBPP16_444 | CNTL_BGR;
200 		break;
201 	default:
202 		WARN_ONCE(true, "Unknown FB format 0x%08x\n",
203 			  fb->format->format);
204 		break;
205 	}
206 
207 	writel(cntl, priv->regs + CLCD_PL111_CNTL);
208 
209 	drm_panel_enable(priv->connector.panel);
210 
211 	drm_crtc_vblank_on(crtc);
212 }
213 
214 void pl111_display_disable(struct drm_simple_display_pipe *pipe)
215 {
216 	struct drm_crtc *crtc = &pipe->crtc;
217 	struct drm_device *drm = crtc->dev;
218 	struct pl111_drm_dev_private *priv = drm->dev_private;
219 
220 	drm_crtc_vblank_off(crtc);
221 
222 	drm_panel_disable(priv->connector.panel);
223 
224 	/* Disable and Power Down */
225 	writel(0, priv->regs + CLCD_PL111_CNTL);
226 
227 	drm_panel_unprepare(priv->connector.panel);
228 
229 	clk_disable_unprepare(priv->clk);
230 }
231 
232 static void pl111_display_update(struct drm_simple_display_pipe *pipe,
233 				 struct drm_plane_state *old_pstate)
234 {
235 	struct drm_crtc *crtc = &pipe->crtc;
236 	struct drm_device *drm = crtc->dev;
237 	struct pl111_drm_dev_private *priv = drm->dev_private;
238 	struct drm_pending_vblank_event *event = crtc->state->event;
239 	struct drm_plane *plane = &pipe->plane;
240 	struct drm_plane_state *pstate = plane->state;
241 	struct drm_framebuffer *fb = pstate->fb;
242 
243 	if (fb) {
244 		u32 addr = pl111_get_fb_offset(pstate);
245 
246 		writel(addr, priv->regs + CLCD_UBAS);
247 	}
248 
249 	if (event) {
250 		crtc->state->event = NULL;
251 
252 		spin_lock_irq(&crtc->dev->event_lock);
253 		if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
254 			drm_crtc_arm_vblank_event(crtc, event);
255 		else
256 			drm_crtc_send_vblank_event(crtc, event);
257 		spin_unlock_irq(&crtc->dev->event_lock);
258 	}
259 }
260 
261 int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc)
262 {
263 	struct pl111_drm_dev_private *priv = drm->dev_private;
264 
265 	writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + CLCD_PL111_IENB);
266 
267 	return 0;
268 }
269 
270 void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc)
271 {
272 	struct pl111_drm_dev_private *priv = drm->dev_private;
273 
274 	writel(0, priv->regs + CLCD_PL111_IENB);
275 }
276 
277 static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe,
278 				    struct drm_plane_state *plane_state)
279 {
280 	return drm_fb_cma_prepare_fb(&pipe->plane, plane_state);
281 }
282 
283 const struct drm_simple_display_pipe_funcs pl111_display_funcs = {
284 	.check = pl111_display_check,
285 	.enable = pl111_display_enable,
286 	.disable = pl111_display_disable,
287 	.update = pl111_display_update,
288 	.prepare_fb = pl111_display_prepare_fb,
289 };
290 
291 int pl111_display_init(struct drm_device *drm)
292 {
293 	struct pl111_drm_dev_private *priv = drm->dev_private;
294 	struct device *dev = drm->dev;
295 	struct device_node *endpoint;
296 	u32 tft_r0b0g0[3];
297 	int ret;
298 	static const u32 formats[] = {
299 		DRM_FORMAT_ABGR8888,
300 		DRM_FORMAT_XBGR8888,
301 		DRM_FORMAT_ARGB8888,
302 		DRM_FORMAT_XRGB8888,
303 		DRM_FORMAT_BGR565,
304 		DRM_FORMAT_RGB565,
305 		DRM_FORMAT_ABGR1555,
306 		DRM_FORMAT_XBGR1555,
307 		DRM_FORMAT_ARGB1555,
308 		DRM_FORMAT_XRGB1555,
309 		DRM_FORMAT_ABGR4444,
310 		DRM_FORMAT_XBGR4444,
311 		DRM_FORMAT_ARGB4444,
312 		DRM_FORMAT_XRGB4444,
313 	};
314 
315 	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
316 	if (!endpoint)
317 		return -ENODEV;
318 
319 	if (of_property_read_u32_array(endpoint,
320 				       "arm,pl11x,tft-r0g0b0-pads",
321 				       tft_r0b0g0,
322 				       ARRAY_SIZE(tft_r0b0g0)) != 0) {
323 		dev_err(dev, "arm,pl11x,tft-r0g0b0-pads should be 3 ints\n");
324 		of_node_put(endpoint);
325 		return -ENOENT;
326 	}
327 	of_node_put(endpoint);
328 
329 	if (tft_r0b0g0[0] != 0 ||
330 	    tft_r0b0g0[1] != 8 ||
331 	    tft_r0b0g0[2] != 16) {
332 		dev_err(dev, "arm,pl11x,tft-r0g0b0-pads != [0,8,16] not yet supported\n");
333 		return -EINVAL;
334 	}
335 
336 	ret = drm_simple_display_pipe_init(drm, &priv->pipe,
337 					   &pl111_display_funcs,
338 					   formats, ARRAY_SIZE(formats),
339 					   &priv->connector.connector);
340 	if (ret)
341 		return ret;
342 
343 	return 0;
344 }
345