Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright 2016 Linaro Ltd.
  3 * Copyright 2016 ZTE Corporation.
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License version 2 as
  7 * published by the Free Software Foundation.
  8 *
  9 */
 10
 11#include <linux/clk.h>
 12#include <linux/component.h>
 13#include <linux/list.h>
 14#include <linux/module.h>
 15#include <linux/of_graph.h>
 16#include <linux/of_platform.h>
 17#include <linux/spinlock.h>
 18
 19#include <drm/drm_atomic_helper.h>
 20#include <drm/drm_crtc.h>
 21#include <drm/drm_crtc_helper.h>
 22#include <drm/drm_fb_cma_helper.h>
 23#include <drm/drm_fb_helper.h>
 24#include <drm/drm_gem_cma_helper.h>
 25#include <drm/drm_of.h>
 26#include <drm/drmP.h>
 27
 28#include "zx_drm_drv.h"
 29#include "zx_vou.h"
 30
 31struct zx_drm_private {
 32	struct drm_fbdev_cma *fbdev;
 33};
 34
 35static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
 36{
 37	struct zx_drm_private *priv = drm->dev_private;
 38
 39	drm_fbdev_cma_hotplug_event(priv->fbdev);
 40}
 41
 42static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
 43	.fb_create = drm_fb_cma_create,
 44	.output_poll_changed = zx_drm_fb_output_poll_changed,
 45	.atomic_check = drm_atomic_helper_check,
 46	.atomic_commit = drm_atomic_helper_commit,
 47};
 48
 49static void zx_drm_lastclose(struct drm_device *drm)
 50{
 51	struct zx_drm_private *priv = drm->dev_private;
 52
 53	drm_fbdev_cma_restore_mode(priv->fbdev);
 54}
 55
 56static const struct file_operations zx_drm_fops = {
 57	.owner = THIS_MODULE,
 58	.open = drm_open,
 59	.release = drm_release,
 60	.unlocked_ioctl = drm_ioctl,
 61#ifdef CONFIG_COMPAT
 62	.compat_ioctl = drm_compat_ioctl,
 63#endif
 64	.poll = drm_poll,
 65	.read = drm_read,
 66	.llseek = noop_llseek,
 67	.mmap = drm_gem_cma_mmap,
 68};
 69
 70static struct drm_driver zx_drm_driver = {
 71	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 72			   DRIVER_ATOMIC,
 73	.lastclose = zx_drm_lastclose,
 74	.get_vblank_counter = drm_vblank_no_hw_counter,
 75	.enable_vblank = zx_vou_enable_vblank,
 76	.disable_vblank = zx_vou_disable_vblank,
 77	.gem_free_object = drm_gem_cma_free_object,
 78	.gem_vm_ops = &drm_gem_cma_vm_ops,
 79	.dumb_create = drm_gem_cma_dumb_create,
 80	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
 81	.dumb_destroy = drm_gem_dumb_destroy,
 82	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 83	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 84	.gem_prime_export = drm_gem_prime_export,
 85	.gem_prime_import = drm_gem_prime_import,
 86	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
 87	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
 88	.gem_prime_vmap = drm_gem_cma_prime_vmap,
 89	.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
 90	.gem_prime_mmap = drm_gem_cma_prime_mmap,
 91	.fops = &zx_drm_fops,
 92	.name = "zx-vou",
 93	.desc = "ZTE VOU Controller DRM",
 94	.date = "20160811",
 95	.major = 1,
 96	.minor = 0,
 97};
 98
 99static int zx_drm_bind(struct device *dev)
100{
101	struct drm_device *drm;
102	struct zx_drm_private *priv;
103	int ret;
104
105	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
106	if (!priv)
107		return -ENOMEM;
108
109	drm = drm_dev_alloc(&zx_drm_driver, dev);
110	if (IS_ERR(drm))
111		return PTR_ERR(drm);
112
113	drm->dev_private = priv;
114	dev_set_drvdata(dev, drm);
115
116	drm_mode_config_init(drm);
117	drm->mode_config.min_width = 16;
118	drm->mode_config.min_height = 16;
119	drm->mode_config.max_width = 4096;
120	drm->mode_config.max_height = 4096;
121	drm->mode_config.funcs = &zx_drm_mode_config_funcs;
122
123	ret = component_bind_all(dev, drm);
124	if (ret) {
125		DRM_DEV_ERROR(dev, "failed to bind all components: %d\n", ret);
126		goto out_unregister;
127	}
128
129	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
130	if (ret < 0) {
131		DRM_DEV_ERROR(dev, "failed to init vblank: %d\n", ret);
132		goto out_unbind;
133	}
134
135	/*
136	 * We will manage irq handler on our own.  In this case, irq_enabled
137	 * need to be true for using vblank core support.
138	 */
139	drm->irq_enabled = true;
140
141	drm_mode_config_reset(drm);
142	drm_kms_helper_poll_init(drm);
143
144	priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
145					 drm->mode_config.num_connector);
146	if (IS_ERR(priv->fbdev)) {
147		ret = PTR_ERR(priv->fbdev);
148		DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret);
149		priv->fbdev = NULL;
150		goto out_poll_fini;
151	}
152
153	ret = drm_dev_register(drm, 0);
154	if (ret)
155		goto out_fbdev_fini;
156
157	return 0;
158
159out_fbdev_fini:
160	if (priv->fbdev) {
161		drm_fbdev_cma_fini(priv->fbdev);
162		priv->fbdev = NULL;
163	}
164out_poll_fini:
165	drm_kms_helper_poll_fini(drm);
166	drm_mode_config_cleanup(drm);
167	drm_vblank_cleanup(drm);
168out_unbind:
169	component_unbind_all(dev, drm);
170out_unregister:
171	dev_set_drvdata(dev, NULL);
172	drm->dev_private = NULL;
173	drm_dev_unref(drm);
174	return ret;
175}
176
177static void zx_drm_unbind(struct device *dev)
178{
179	struct drm_device *drm = dev_get_drvdata(dev);
180	struct zx_drm_private *priv = drm->dev_private;
181
182	drm_dev_unregister(drm);
183	if (priv->fbdev) {
184		drm_fbdev_cma_fini(priv->fbdev);
185		priv->fbdev = NULL;
186	}
187	drm_kms_helper_poll_fini(drm);
188	drm_mode_config_cleanup(drm);
189	drm_vblank_cleanup(drm);
190	component_unbind_all(dev, drm);
191	dev_set_drvdata(dev, NULL);
192	drm->dev_private = NULL;
193	drm_dev_unref(drm);
194}
195
196static const struct component_master_ops zx_drm_master_ops = {
197	.bind = zx_drm_bind,
198	.unbind = zx_drm_unbind,
199};
200
201static int compare_of(struct device *dev, void *data)
202{
203	return dev->of_node == data;
204}
205
206static int zx_drm_probe(struct platform_device *pdev)
207{
208	struct device *dev = &pdev->dev;
209	struct device_node *parent = dev->of_node;
210	struct device_node *child;
211	struct component_match *match = NULL;
212	int ret;
213
214	ret = of_platform_populate(parent, NULL, NULL, dev);
215	if (ret)
216		return ret;
217
218	for_each_available_child_of_node(parent, child) {
219		component_match_add(dev, &match, compare_of, child);
220		of_node_put(child);
221	}
222
223	return component_master_add_with_match(dev, &zx_drm_master_ops, match);
224}
225
226static int zx_drm_remove(struct platform_device *pdev)
227{
228	component_master_del(&pdev->dev, &zx_drm_master_ops);
229	return 0;
230}
231
232static const struct of_device_id zx_drm_of_match[] = {
233	{ .compatible = "zte,zx296718-vou", },
234	{ /* end */ },
235};
236MODULE_DEVICE_TABLE(of, zx_drm_of_match);
237
238static struct platform_driver zx_drm_platform_driver = {
239	.probe = zx_drm_probe,
240	.remove = zx_drm_remove,
241	.driver	= {
242		.name = "zx-drm",
243		.of_match_table	= zx_drm_of_match,
244	},
245};
246
247static struct platform_driver *drivers[] = {
248	&zx_crtc_driver,
249	&zx_hdmi_driver,
250	&zx_drm_platform_driver,
251};
252
253static int zx_drm_init(void)
254{
255	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
256}
257module_init(zx_drm_init);
258
259static void zx_drm_exit(void)
260{
261	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
262}
263module_exit(zx_drm_exit);
264
265MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
266MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
267MODULE_LICENSE("GPL v2");