]>
Commit | Line | Data |
---|---|---|
0a886f59 SG |
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 | ||
31 | struct zx_drm_private { | |
32 | struct drm_fbdev_cma *fbdev; | |
33 | }; | |
34 | ||
35 | static 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 | ||
42 | static 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 | ||
49 | static 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 | ||
d55f7e5d | 56 | DEFINE_DRM_GEM_CMA_FOPS(zx_drm_fops); |
0a886f59 SG |
57 | |
58 | static struct drm_driver zx_drm_driver = { | |
59 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | | |
60 | DRIVER_ATOMIC, | |
61 | .lastclose = zx_drm_lastclose, | |
98755a51 | 62 | .gem_free_object_unlocked = drm_gem_cma_free_object, |
0a886f59 SG |
63 | .gem_vm_ops = &drm_gem_cma_vm_ops, |
64 | .dumb_create = drm_gem_cma_dumb_create, | |
65 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | |
66 | .dumb_destroy = drm_gem_dumb_destroy, | |
67 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | |
68 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | |
69 | .gem_prime_export = drm_gem_prime_export, | |
70 | .gem_prime_import = drm_gem_prime_import, | |
71 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | |
72 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | |
73 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | |
74 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | |
75 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | |
76 | .fops = &zx_drm_fops, | |
77 | .name = "zx-vou", | |
78 | .desc = "ZTE VOU Controller DRM", | |
79 | .date = "20160811", | |
80 | .major = 1, | |
81 | .minor = 0, | |
82 | }; | |
83 | ||
84 | static int zx_drm_bind(struct device *dev) | |
85 | { | |
86 | struct drm_device *drm; | |
87 | struct zx_drm_private *priv; | |
88 | int ret; | |
89 | ||
90 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
91 | if (!priv) | |
92 | return -ENOMEM; | |
93 | ||
94 | drm = drm_dev_alloc(&zx_drm_driver, dev); | |
72282a88 DC |
95 | if (IS_ERR(drm)) |
96 | return PTR_ERR(drm); | |
0a886f59 SG |
97 | |
98 | drm->dev_private = priv; | |
99 | dev_set_drvdata(dev, drm); | |
100 | ||
101 | drm_mode_config_init(drm); | |
102 | drm->mode_config.min_width = 16; | |
103 | drm->mode_config.min_height = 16; | |
104 | drm->mode_config.max_width = 4096; | |
105 | drm->mode_config.max_height = 4096; | |
106 | drm->mode_config.funcs = &zx_drm_mode_config_funcs; | |
107 | ||
108 | ret = component_bind_all(dev, drm); | |
109 | if (ret) { | |
110 | DRM_DEV_ERROR(dev, "failed to bind all components: %d\n", ret); | |
111 | goto out_unregister; | |
112 | } | |
113 | ||
114 | ret = drm_vblank_init(drm, drm->mode_config.num_crtc); | |
115 | if (ret < 0) { | |
116 | DRM_DEV_ERROR(dev, "failed to init vblank: %d\n", ret); | |
117 | goto out_unbind; | |
118 | } | |
119 | ||
120 | /* | |
121 | * We will manage irq handler on our own. In this case, irq_enabled | |
122 | * need to be true for using vblank core support. | |
123 | */ | |
124 | drm->irq_enabled = true; | |
125 | ||
126 | drm_mode_config_reset(drm); | |
127 | drm_kms_helper_poll_init(drm); | |
128 | ||
e4563f6b | 129 | priv->fbdev = drm_fbdev_cma_init(drm, 32, |
0a886f59 SG |
130 | drm->mode_config.num_connector); |
131 | if (IS_ERR(priv->fbdev)) { | |
132 | ret = PTR_ERR(priv->fbdev); | |
133 | DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret); | |
134 | priv->fbdev = NULL; | |
135 | goto out_poll_fini; | |
136 | } | |
137 | ||
138 | ret = drm_dev_register(drm, 0); | |
139 | if (ret) | |
140 | goto out_fbdev_fini; | |
141 | ||
142 | return 0; | |
143 | ||
144 | out_fbdev_fini: | |
145 | if (priv->fbdev) { | |
146 | drm_fbdev_cma_fini(priv->fbdev); | |
147 | priv->fbdev = NULL; | |
148 | } | |
149 | out_poll_fini: | |
150 | drm_kms_helper_poll_fini(drm); | |
151 | drm_mode_config_cleanup(drm); | |
0a886f59 SG |
152 | out_unbind: |
153 | component_unbind_all(dev, drm); | |
154 | out_unregister: | |
155 | dev_set_drvdata(dev, NULL); | |
156 | drm->dev_private = NULL; | |
157 | drm_dev_unref(drm); | |
158 | return ret; | |
159 | } | |
160 | ||
161 | static void zx_drm_unbind(struct device *dev) | |
162 | { | |
163 | struct drm_device *drm = dev_get_drvdata(dev); | |
164 | struct zx_drm_private *priv = drm->dev_private; | |
165 | ||
166 | drm_dev_unregister(drm); | |
167 | if (priv->fbdev) { | |
168 | drm_fbdev_cma_fini(priv->fbdev); | |
169 | priv->fbdev = NULL; | |
170 | } | |
171 | drm_kms_helper_poll_fini(drm); | |
172 | drm_mode_config_cleanup(drm); | |
0a886f59 SG |
173 | component_unbind_all(dev, drm); |
174 | dev_set_drvdata(dev, NULL); | |
175 | drm->dev_private = NULL; | |
176 | drm_dev_unref(drm); | |
177 | } | |
178 | ||
179 | static const struct component_master_ops zx_drm_master_ops = { | |
180 | .bind = zx_drm_bind, | |
181 | .unbind = zx_drm_unbind, | |
182 | }; | |
183 | ||
184 | static int compare_of(struct device *dev, void *data) | |
185 | { | |
186 | return dev->of_node == data; | |
187 | } | |
188 | ||
189 | static int zx_drm_probe(struct platform_device *pdev) | |
190 | { | |
191 | struct device *dev = &pdev->dev; | |
192 | struct device_node *parent = dev->of_node; | |
193 | struct device_node *child; | |
194 | struct component_match *match = NULL; | |
195 | int ret; | |
196 | ||
f3ca01d3 | 197 | ret = devm_of_platform_populate(dev); |
0a886f59 SG |
198 | if (ret) |
199 | return ret; | |
200 | ||
201 | for_each_available_child_of_node(parent, child) { | |
202 | component_match_add(dev, &match, compare_of, child); | |
203 | of_node_put(child); | |
204 | } | |
205 | ||
206 | return component_master_add_with_match(dev, &zx_drm_master_ops, match); | |
207 | } | |
208 | ||
209 | static int zx_drm_remove(struct platform_device *pdev) | |
210 | { | |
211 | component_master_del(&pdev->dev, &zx_drm_master_ops); | |
212 | return 0; | |
213 | } | |
214 | ||
215 | static const struct of_device_id zx_drm_of_match[] = { | |
216 | { .compatible = "zte,zx296718-vou", }, | |
217 | { /* end */ }, | |
218 | }; | |
219 | MODULE_DEVICE_TABLE(of, zx_drm_of_match); | |
220 | ||
221 | static struct platform_driver zx_drm_platform_driver = { | |
222 | .probe = zx_drm_probe, | |
223 | .remove = zx_drm_remove, | |
224 | .driver = { | |
225 | .name = "zx-drm", | |
226 | .of_match_table = zx_drm_of_match, | |
227 | }, | |
228 | }; | |
229 | ||
230 | static struct platform_driver *drivers[] = { | |
231 | &zx_crtc_driver, | |
232 | &zx_hdmi_driver, | |
098988cb | 233 | &zx_tvenc_driver, |
6911498d | 234 | &zx_vga_driver, |
0a886f59 SG |
235 | &zx_drm_platform_driver, |
236 | }; | |
237 | ||
238 | static int zx_drm_init(void) | |
239 | { | |
240 | return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); | |
241 | } | |
242 | module_init(zx_drm_init); | |
243 | ||
244 | static void zx_drm_exit(void) | |
245 | { | |
246 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); | |
247 | } | |
248 | module_exit(zx_drm_exit); | |
249 | ||
250 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); | |
251 | MODULE_DESCRIPTION("ZTE ZX VOU DRM driver"); | |
252 | MODULE_LICENSE("GPL v2"); |