1 /*
2  * Copyright (C) 2012 Russell King
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 #include <linux/clk.h>
9 #include <linux/module.h>
10 #include <drm/drmP.h>
11 #include <drm/drm_crtc_helper.h>
12 #include "armada_crtc.h"
13 #include "armada_drm.h"
14 #include "armada_gem.h"
15 #include "armada_hw.h"
16 #include <drm/armada_drm.h>
17 #include "armada_ioctlP.h"
18 
19 #ifdef CONFIG_DRM_ARMADA_TDA1998X
20 #include <drm/i2c/tda998x.h>
21 #include "armada_slave.h"
22 
23 static struct tda998x_encoder_params params = {
24 	/* With 0x24, there is no translation between vp_out and int_vp
25 	FB	LCD out	Pins	VIP	Int Vp
26 	R:23:16	R:7:0	VPC7:0	7:0	7:0[R]
27 	G:15:8	G:15:8	VPB7:0	23:16	23:16[G]
28 	B:7:0	B:23:16	VPA7:0	15:8	15:8[B]
29 	*/
30 	.swap_a = 2,
31 	.swap_b = 3,
32 	.swap_c = 4,
33 	.swap_d = 5,
34 	.swap_e = 0,
35 	.swap_f = 1,
36 	.audio_cfg = BIT(2),
37 	.audio_frame[1] = 1,
38 	.audio_format = AFMT_SPDIF,
39 	.audio_sample_rate = 44100,
40 };
41 
42 static const struct armada_drm_slave_config tda19988_config = {
43 	.i2c_adapter_id = 0,
44 	.crtcs = 1 << 0, /* Only LCD0 at the moment */
45 	.polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT,
46 	.interlace_allowed = true,
47 	.info = {
48 		.type = "tda998x",
49 		.addr = 0x70,
50 		.platform_data = &params,
51 	},
52 };
53 #endif
54 
55 static void armada_drm_unref_work(struct work_struct *work)
56 {
57 	struct armada_private *priv =
58 		container_of(work, struct armada_private, fb_unref_work);
59 	struct drm_framebuffer *fb;
60 
61 	while (kfifo_get(&priv->fb_unref, &fb))
62 		drm_framebuffer_unreference(fb);
63 }
64 
65 /* Must be called with dev->event_lock held */
66 void __armada_drm_queue_unref_work(struct drm_device *dev,
67 	struct drm_framebuffer *fb)
68 {
69 	struct armada_private *priv = dev->dev_private;
70 
71 	/*
72 	 * Yes, we really must jump through these hoops just to store a
73 	 * _pointer_ to something into the kfifo.  This is utterly insane
74 	 * and idiotic, because it kfifo requires the _data_ pointed to by
75 	 * the pointer const, not the pointer itself.  Not only that, but
76 	 * you have to pass a pointer _to_ the pointer you want stored.
77 	 */
78 	const struct drm_framebuffer *silly_api_alert = fb;
79 	WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
80 	schedule_work(&priv->fb_unref_work);
81 }
82 
83 void armada_drm_queue_unref_work(struct drm_device *dev,
84 	struct drm_framebuffer *fb)
85 {
86 	unsigned long flags;
87 
88 	spin_lock_irqsave(&dev->event_lock, flags);
89 	__armada_drm_queue_unref_work(dev, fb);
90 	spin_unlock_irqrestore(&dev->event_lock, flags);
91 }
92 
93 static int armada_drm_load(struct drm_device *dev, unsigned long flags)
94 {
95 	const struct platform_device_id *id;
96 	struct armada_private *priv;
97 	struct resource *res[ARRAY_SIZE(priv->dcrtc)];
98 	struct resource *mem = NULL;
99 	int ret, n, i;
100 
101 	memset(res, 0, sizeof(res));
102 
103 	for (n = i = 0; ; n++) {
104 		struct resource *r = platform_get_resource(dev->platformdev,
105 							   IORESOURCE_MEM, n);
106 		if (!r)
107 			break;
108 
109 		/* Resources above 64K are graphics memory */
110 		if (resource_size(r) > SZ_64K)
111 			mem = r;
112 		else if (i < ARRAY_SIZE(priv->dcrtc))
113 			res[i++] = r;
114 		else
115 			return -EINVAL;
116 	}
117 
118 	if (!res[0] || !mem)
119 		return -ENXIO;
120 
121 	if (!devm_request_mem_region(dev->dev, mem->start,
122 			resource_size(mem), "armada-drm"))
123 		return -EBUSY;
124 
125 	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
126 	if (!priv) {
127 		DRM_ERROR("failed to allocate private\n");
128 		return -ENOMEM;
129 	}
130 
131 	dev->dev_private = priv;
132 
133 	/* Get the implementation specific driver data. */
134 	id = platform_get_device_id(dev->platformdev);
135 	if (!id)
136 		return -ENXIO;
137 
138 	priv->variant = (struct armada_variant *)id->driver_data;
139 
140 	ret = priv->variant->init(priv, dev->dev);
141 	if (ret)
142 		return ret;
143 
144 	INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);
145 	INIT_KFIFO(priv->fb_unref);
146 
147 	/* Mode setting support */
148 	drm_mode_config_init(dev);
149 	dev->mode_config.min_width = 320;
150 	dev->mode_config.min_height = 200;
151 
152 	/*
153 	 * With vscale enabled, the maximum width is 1920 due to the
154 	 * 1920 by 3 lines RAM
155 	 */
156 	dev->mode_config.max_width = 1920;
157 	dev->mode_config.max_height = 2048;
158 
159 	dev->mode_config.preferred_depth = 24;
160 	dev->mode_config.funcs = &armada_drm_mode_config_funcs;
161 	drm_mm_init(&priv->linear, mem->start, resource_size(mem));
162 
163 	/* Create all LCD controllers */
164 	for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) {
165 		if (!res[n])
166 			break;
167 
168 		ret = armada_drm_crtc_create(dev, n, res[n]);
169 		if (ret)
170 			goto err_kms;
171 	}
172 
173 #ifdef CONFIG_DRM_ARMADA_TDA1998X
174 	ret = armada_drm_connector_slave_create(dev, &tda19988_config);
175 	if (ret)
176 		goto err_kms;
177 #endif
178 
179 	ret = drm_vblank_init(dev, n);
180 	if (ret)
181 		goto err_kms;
182 
183 	ret = drm_irq_install(dev);
184 	if (ret)
185 		goto err_kms;
186 
187 	dev->vblank_disable_allowed = 1;
188 
189 	ret = armada_fbdev_init(dev);
190 	if (ret)
191 		goto err_irq;
192 
193 	drm_kms_helper_poll_init(dev);
194 
195 	return 0;
196 
197  err_irq:
198 	drm_irq_uninstall(dev);
199  err_kms:
200 	drm_mode_config_cleanup(dev);
201 	drm_mm_takedown(&priv->linear);
202 	flush_work(&priv->fb_unref_work);
203 
204 	return ret;
205 }
206 
207 static int armada_drm_unload(struct drm_device *dev)
208 {
209 	struct armada_private *priv = dev->dev_private;
210 
211 	drm_kms_helper_poll_fini(dev);
212 	armada_fbdev_fini(dev);
213 	drm_irq_uninstall(dev);
214 	drm_mode_config_cleanup(dev);
215 	drm_mm_takedown(&priv->linear);
216 	flush_work(&priv->fb_unref_work);
217 	dev->dev_private = NULL;
218 
219 	return 0;
220 }
221 
222 void armada_drm_vbl_event_add(struct armada_crtc *dcrtc,
223 	struct armada_vbl_event *evt)
224 {
225 	unsigned long flags;
226 
227 	spin_lock_irqsave(&dcrtc->irq_lock, flags);
228 	if (list_empty(&evt->node)) {
229 		list_add_tail(&evt->node, &dcrtc->vbl_list);
230 
231 		drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
232 	}
233 	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
234 }
235 
236 void armada_drm_vbl_event_remove(struct armada_crtc *dcrtc,
237 	struct armada_vbl_event *evt)
238 {
239 	if (!list_empty(&evt->node)) {
240 		list_del_init(&evt->node);
241 		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
242 	}
243 }
244 
245 void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *dcrtc,
246 	struct armada_vbl_event *evt)
247 {
248 	unsigned long flags;
249 
250 	spin_lock_irqsave(&dcrtc->irq_lock, flags);
251 	armada_drm_vbl_event_remove(dcrtc, evt);
252 	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
253 }
254 
255 /* These are called under the vbl_lock. */
256 static int armada_drm_enable_vblank(struct drm_device *dev, int crtc)
257 {
258 	struct armada_private *priv = dev->dev_private;
259 	armada_drm_crtc_enable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
260 	return 0;
261 }
262 
263 static void armada_drm_disable_vblank(struct drm_device *dev, int crtc)
264 {
265 	struct armada_private *priv = dev->dev_private;
266 	armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
267 }
268 
269 static irqreturn_t armada_drm_irq_handler(int irq, void *arg)
270 {
271 	struct drm_device *dev = arg;
272 	struct armada_private *priv = dev->dev_private;
273 	struct armada_crtc *dcrtc = priv->dcrtc[0];
274 	uint32_t v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
275 	irqreturn_t handled = IRQ_NONE;
276 
277 	/*
278 	 * This is rediculous - rather than writing bits to clear, we
279 	 * have to set the actual status register value.  This is racy.
280 	 */
281 	writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
282 
283 	/* Mask out those interrupts we haven't enabled */
284 	v = stat & dcrtc->irq_ena;
285 
286 	if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
287 		armada_drm_crtc_irq(dcrtc, stat);
288 		handled = IRQ_HANDLED;
289 	}
290 
291 	return handled;
292 }
293 
294 static int armada_drm_irq_postinstall(struct drm_device *dev)
295 {
296 	struct armada_private *priv = dev->dev_private;
297 	struct armada_crtc *dcrtc = priv->dcrtc[0];
298 
299 	spin_lock_irq(&dev->vbl_lock);
300 	writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
301 	writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
302 	spin_unlock_irq(&dev->vbl_lock);
303 
304 	return 0;
305 }
306 
307 static void armada_drm_irq_uninstall(struct drm_device *dev)
308 {
309 	struct armada_private *priv = dev->dev_private;
310 	struct armada_crtc *dcrtc = priv->dcrtc[0];
311 
312 	writel(0, dcrtc->base + LCD_SPU_IRQ_ENA);
313 }
314 
315 static struct drm_ioctl_desc armada_ioctls[] = {
316 	DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,
317 		DRM_UNLOCKED),
318 	DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl,
319 		DRM_UNLOCKED),
320 	DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl,
321 		DRM_UNLOCKED),
322 };
323 
324 static void armada_drm_lastclose(struct drm_device *dev)
325 {
326 	armada_fbdev_lastclose(dev);
327 }
328 
329 static const struct file_operations armada_drm_fops = {
330 	.owner			= THIS_MODULE,
331 	.llseek			= no_llseek,
332 	.read			= drm_read,
333 	.poll			= drm_poll,
334 	.unlocked_ioctl		= drm_ioctl,
335 	.mmap			= drm_gem_mmap,
336 	.open			= drm_open,
337 	.release		= drm_release,
338 };
339 
340 static struct drm_driver armada_drm_driver = {
341 	.load			= armada_drm_load,
342 	.open			= NULL,
343 	.preclose		= NULL,
344 	.postclose		= NULL,
345 	.lastclose		= armada_drm_lastclose,
346 	.unload			= armada_drm_unload,
347 	.get_vblank_counter	= drm_vblank_count,
348 	.enable_vblank		= armada_drm_enable_vblank,
349 	.disable_vblank		= armada_drm_disable_vblank,
350 	.irq_handler		= armada_drm_irq_handler,
351 	.irq_postinstall	= armada_drm_irq_postinstall,
352 	.irq_uninstall		= armada_drm_irq_uninstall,
353 #ifdef CONFIG_DEBUG_FS
354 	.debugfs_init		= armada_drm_debugfs_init,
355 	.debugfs_cleanup	= armada_drm_debugfs_cleanup,
356 #endif
357 	.gem_free_object	= armada_gem_free_object,
358 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
359 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
360 	.gem_prime_export	= armada_gem_prime_export,
361 	.gem_prime_import	= armada_gem_prime_import,
362 	.dumb_create		= armada_gem_dumb_create,
363 	.dumb_map_offset	= armada_gem_dumb_map_offset,
364 	.dumb_destroy		= armada_gem_dumb_destroy,
365 	.gem_vm_ops		= &armada_gem_vm_ops,
366 	.major			= 1,
367 	.minor			= 0,
368 	.name			= "armada-drm",
369 	.desc			= "Armada SoC DRM",
370 	.date			= "20120730",
371 	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
372 				  DRIVER_HAVE_IRQ | DRIVER_PRIME,
373 	.ioctls			= armada_ioctls,
374 	.fops			= &armada_drm_fops,
375 };
376 
377 static int armada_drm_probe(struct platform_device *pdev)
378 {
379 	return drm_platform_init(&armada_drm_driver, pdev);
380 }
381 
382 static int armada_drm_remove(struct platform_device *pdev)
383 {
384 	drm_platform_exit(&armada_drm_driver, pdev);
385 	return 0;
386 }
387 
388 static const struct platform_device_id armada_drm_platform_ids[] = {
389 	{
390 		.name		= "armada-drm",
391 		.driver_data	= (unsigned long)&armada510_ops,
392 	}, {
393 		.name		= "armada-510-drm",
394 		.driver_data	= (unsigned long)&armada510_ops,
395 	},
396 	{ },
397 };
398 MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);
399 
400 static struct platform_driver armada_drm_platform_driver = {
401 	.probe	= armada_drm_probe,
402 	.remove	= armada_drm_remove,
403 	.driver	= {
404 		.name	= "armada-drm",
405 		.owner	= THIS_MODULE,
406 	},
407 	.id_table = armada_drm_platform_ids,
408 };
409 
410 static int __init armada_drm_init(void)
411 {
412 	armada_drm_driver.num_ioctls = DRM_ARRAY_SIZE(armada_ioctls);
413 	return platform_driver_register(&armada_drm_platform_driver);
414 }
415 module_init(armada_drm_init);
416 
417 static void __exit armada_drm_exit(void)
418 {
419 	platform_driver_unregister(&armada_drm_platform_driver);
420 }
421 module_exit(armada_drm_exit);
422 
423 MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
424 MODULE_DESCRIPTION("Armada DRM Driver");
425 MODULE_LICENSE("GPL");
426 MODULE_ALIAS("platform:armada-drm");
427