Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
Loading...
Note: File does not exist in v3.1.
  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
 23static 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
 42static 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
 55static 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 */
 66void __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	WARN_ON(!kfifo_put(&priv->fb_unref, fb));
 72	schedule_work(&priv->fb_unref_work);
 73}
 74
 75void armada_drm_queue_unref_work(struct drm_device *dev,
 76	struct drm_framebuffer *fb)
 77{
 78	unsigned long flags;
 79
 80	spin_lock_irqsave(&dev->event_lock, flags);
 81	__armada_drm_queue_unref_work(dev, fb);
 82	spin_unlock_irqrestore(&dev->event_lock, flags);
 83}
 84
 85static int armada_drm_load(struct drm_device *dev, unsigned long flags)
 86{
 87	const struct platform_device_id *id;
 88	struct armada_private *priv;
 89	struct resource *res[ARRAY_SIZE(priv->dcrtc)];
 90	struct resource *mem = NULL;
 91	int ret, n, i;
 92
 93	memset(res, 0, sizeof(res));
 94
 95	for (n = i = 0; ; n++) {
 96		struct resource *r = platform_get_resource(dev->platformdev,
 97							   IORESOURCE_MEM, n);
 98		if (!r)
 99			break;
100
101		/* Resources above 64K are graphics memory */
102		if (resource_size(r) > SZ_64K)
103			mem = r;
104		else if (i < ARRAY_SIZE(priv->dcrtc))
105			res[i++] = r;
106		else
107			return -EINVAL;
108	}
109
110	if (!res[0] || !mem)
111		return -ENXIO;
112
113	if (!devm_request_mem_region(dev->dev, mem->start,
114			resource_size(mem), "armada-drm"))
115		return -EBUSY;
116
117	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
118	if (!priv) {
119		DRM_ERROR("failed to allocate private\n");
120		return -ENOMEM;
121	}
122
123	platform_set_drvdata(dev->platformdev, dev);
124	dev->dev_private = priv;
125
126	/* Get the implementation specific driver data. */
127	id = platform_get_device_id(dev->platformdev);
128	if (!id)
129		return -ENXIO;
130
131	priv->variant = (struct armada_variant *)id->driver_data;
132
133	ret = priv->variant->init(priv, dev->dev);
134	if (ret)
135		return ret;
136
137	INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);
138	INIT_KFIFO(priv->fb_unref);
139
140	/* Mode setting support */
141	drm_mode_config_init(dev);
142	dev->mode_config.min_width = 320;
143	dev->mode_config.min_height = 200;
144
145	/*
146	 * With vscale enabled, the maximum width is 1920 due to the
147	 * 1920 by 3 lines RAM
148	 */
149	dev->mode_config.max_width = 1920;
150	dev->mode_config.max_height = 2048;
151
152	dev->mode_config.preferred_depth = 24;
153	dev->mode_config.funcs = &armada_drm_mode_config_funcs;
154	drm_mm_init(&priv->linear, mem->start, resource_size(mem));
155
156	/* Create all LCD controllers */
157	for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) {
158		if (!res[n])
159			break;
160
161		ret = armada_drm_crtc_create(dev, n, res[n]);
162		if (ret)
163			goto err_kms;
164	}
165
166#ifdef CONFIG_DRM_ARMADA_TDA1998X
167	ret = armada_drm_connector_slave_create(dev, &tda19988_config);
168	if (ret)
169		goto err_kms;
170#endif
171
172	ret = drm_vblank_init(dev, n);
173	if (ret)
174		goto err_kms;
175
176	ret = drm_irq_install(dev);
177	if (ret)
178		goto err_kms;
179
180	dev->vblank_disable_allowed = 1;
181
182	ret = armada_fbdev_init(dev);
183	if (ret)
184		goto err_irq;
185
186	drm_kms_helper_poll_init(dev);
187
188	return 0;
189
190 err_irq:
191	drm_irq_uninstall(dev);
192 err_kms:
193	drm_mode_config_cleanup(dev);
194	drm_mm_takedown(&priv->linear);
195	flush_work(&priv->fb_unref_work);
196
197	return ret;
198}
199
200static int armada_drm_unload(struct drm_device *dev)
201{
202	struct armada_private *priv = dev->dev_private;
203
204	drm_kms_helper_poll_fini(dev);
205	armada_fbdev_fini(dev);
206	drm_irq_uninstall(dev);
207	drm_mode_config_cleanup(dev);
208	drm_mm_takedown(&priv->linear);
209	flush_work(&priv->fb_unref_work);
210	dev->dev_private = NULL;
211
212	return 0;
213}
214
215void armada_drm_vbl_event_add(struct armada_crtc *dcrtc,
216	struct armada_vbl_event *evt)
217{
218	unsigned long flags;
219
220	spin_lock_irqsave(&dcrtc->irq_lock, flags);
221	if (list_empty(&evt->node)) {
222		list_add_tail(&evt->node, &dcrtc->vbl_list);
223
224		drm_vblank_get(dcrtc->crtc.dev, dcrtc->num);
225	}
226	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
227}
228
229void armada_drm_vbl_event_remove(struct armada_crtc *dcrtc,
230	struct armada_vbl_event *evt)
231{
232	if (!list_empty(&evt->node)) {
233		list_del_init(&evt->node);
234		drm_vblank_put(dcrtc->crtc.dev, dcrtc->num);
235	}
236}
237
238void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *dcrtc,
239	struct armada_vbl_event *evt)
240{
241	unsigned long flags;
242
243	spin_lock_irqsave(&dcrtc->irq_lock, flags);
244	armada_drm_vbl_event_remove(dcrtc, evt);
245	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
246}
247
248/* These are called under the vbl_lock. */
249static int armada_drm_enable_vblank(struct drm_device *dev, int crtc)
250{
251	struct armada_private *priv = dev->dev_private;
252	armada_drm_crtc_enable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
253	return 0;
254}
255
256static void armada_drm_disable_vblank(struct drm_device *dev, int crtc)
257{
258	struct armada_private *priv = dev->dev_private;
259	armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
260}
261
262static irqreturn_t armada_drm_irq_handler(int irq, void *arg)
263{
264	struct drm_device *dev = arg;
265	struct armada_private *priv = dev->dev_private;
266	struct armada_crtc *dcrtc = priv->dcrtc[0];
267	uint32_t v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
268	irqreturn_t handled = IRQ_NONE;
269
270	/*
271	 * This is rediculous - rather than writing bits to clear, we
272	 * have to set the actual status register value.  This is racy.
273	 */
274	writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
275
276	/* Mask out those interrupts we haven't enabled */
277	v = stat & dcrtc->irq_ena;
278
279	if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
280		armada_drm_crtc_irq(dcrtc, stat);
281		handled = IRQ_HANDLED;
282	}
283
284	return handled;
285}
286
287static int armada_drm_irq_postinstall(struct drm_device *dev)
288{
289	struct armada_private *priv = dev->dev_private;
290	struct armada_crtc *dcrtc = priv->dcrtc[0];
291
292	spin_lock_irq(&dev->vbl_lock);
293	writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
294	writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
295	spin_unlock_irq(&dev->vbl_lock);
296
297	return 0;
298}
299
300static void armada_drm_irq_uninstall(struct drm_device *dev)
301{
302	struct armada_private *priv = dev->dev_private;
303	struct armada_crtc *dcrtc = priv->dcrtc[0];
304
305	writel(0, dcrtc->base + LCD_SPU_IRQ_ENA);
306}
307
308static struct drm_ioctl_desc armada_ioctls[] = {
309	DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,
310		DRM_UNLOCKED),
311	DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl,
312		DRM_UNLOCKED),
313	DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl,
314		DRM_UNLOCKED),
315};
316
317static void armada_drm_lastclose(struct drm_device *dev)
318{
319	armada_fbdev_lastclose(dev);
320}
321
322static const struct file_operations armada_drm_fops = {
323	.owner			= THIS_MODULE,
324	.llseek			= no_llseek,
325	.read			= drm_read,
326	.poll			= drm_poll,
327	.unlocked_ioctl		= drm_ioctl,
328	.mmap			= drm_gem_mmap,
329	.open			= drm_open,
330	.release		= drm_release,
331};
332
333static struct drm_driver armada_drm_driver = {
334	.load			= armada_drm_load,
335	.open			= NULL,
336	.preclose		= NULL,
337	.postclose		= NULL,
338	.lastclose		= armada_drm_lastclose,
339	.unload			= armada_drm_unload,
340	.get_vblank_counter	= drm_vblank_count,
341	.enable_vblank		= armada_drm_enable_vblank,
342	.disable_vblank		= armada_drm_disable_vblank,
343	.irq_handler		= armada_drm_irq_handler,
344	.irq_postinstall	= armada_drm_irq_postinstall,
345	.irq_uninstall		= armada_drm_irq_uninstall,
346#ifdef CONFIG_DEBUG_FS
347	.debugfs_init		= armada_drm_debugfs_init,
348	.debugfs_cleanup	= armada_drm_debugfs_cleanup,
349#endif
350	.gem_free_object	= armada_gem_free_object,
351	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
352	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
353	.gem_prime_export	= armada_gem_prime_export,
354	.gem_prime_import	= armada_gem_prime_import,
355	.dumb_create		= armada_gem_dumb_create,
356	.dumb_map_offset	= armada_gem_dumb_map_offset,
357	.dumb_destroy		= armada_gem_dumb_destroy,
358	.gem_vm_ops		= &armada_gem_vm_ops,
359	.major			= 1,
360	.minor			= 0,
361	.name			= "armada-drm",
362	.desc			= "Armada SoC DRM",
363	.date			= "20120730",
364	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
365				  DRIVER_HAVE_IRQ | DRIVER_PRIME,
366	.ioctls			= armada_ioctls,
367	.fops			= &armada_drm_fops,
368};
369
370static int armada_drm_probe(struct platform_device *pdev)
371{
372	return drm_platform_init(&armada_drm_driver, pdev);
373}
374
375static int armada_drm_remove(struct platform_device *pdev)
376{
377	drm_put_dev(platform_get_drvdata(pdev));
378	return 0;
379}
380
381static const struct platform_device_id armada_drm_platform_ids[] = {
382	{
383		.name		= "armada-drm",
384		.driver_data	= (unsigned long)&armada510_ops,
385	}, {
386		.name		= "armada-510-drm",
387		.driver_data	= (unsigned long)&armada510_ops,
388	},
389	{ },
390};
391MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);
392
393static struct platform_driver armada_drm_platform_driver = {
394	.probe	= armada_drm_probe,
395	.remove	= armada_drm_remove,
396	.driver	= {
397		.name	= "armada-drm",
398		.owner	= THIS_MODULE,
399	},
400	.id_table = armada_drm_platform_ids,
401};
402
403static int __init armada_drm_init(void)
404{
405	armada_drm_driver.num_ioctls = DRM_ARRAY_SIZE(armada_ioctls);
406	return platform_driver_register(&armada_drm_platform_driver);
407}
408module_init(armada_drm_init);
409
410static void __exit armada_drm_exit(void)
411{
412	platform_driver_unregister(&armada_drm_platform_driver);
413}
414module_exit(armada_drm_exit);
415
416MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
417MODULE_DESCRIPTION("Armada DRM Driver");
418MODULE_LICENSE("GPL");
419MODULE_ALIAS("platform:armada-drm");