1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
4 | * Authors: |
5 | * Inki Dae <inki.dae@samsung.com> |
6 | * Joonyoung Shim <jy0922.shim@samsung.com> |
7 | * Seung-Woo Kim <sw0312.kim@samsung.com> |
8 | */ |
9 | |
10 | #include <linux/component.h> |
11 | #include <linux/dma-mapping.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/pm_runtime.h> |
14 | #include <linux/uaccess.h> |
15 | |
16 | #include <drm/drm_atomic.h> |
17 | #include <drm/drm_atomic_helper.h> |
18 | #include <drm/drm_drv.h> |
19 | #include <drm/drm_file.h> |
20 | #include <drm/drm_fourcc.h> |
21 | #include <drm/drm_ioctl.h> |
22 | #include <drm/drm_probe_helper.h> |
23 | #include <drm/drm_vblank.h> |
24 | #include <drm/exynos_drm.h> |
25 | |
26 | #include "exynos_drm_drv.h" |
27 | #include "exynos_drm_fb.h" |
28 | #include "exynos_drm_fbdev.h" |
29 | #include "exynos_drm_g2d.h" |
30 | #include "exynos_drm_gem.h" |
31 | #include "exynos_drm_ipp.h" |
32 | #include "exynos_drm_plane.h" |
33 | #include "exynos_drm_vidi.h" |
34 | |
35 | #define DRIVER_NAME "exynos" |
36 | #define DRIVER_DESC "Samsung SoC DRM" |
37 | #define DRIVER_DATE "20180330" |
38 | |
39 | /* |
40 | * Interface history: |
41 | * |
42 | * 1.0 - Original version |
43 | * 1.1 - Upgrade IPP driver to version 2.0 |
44 | */ |
45 | #define DRIVER_MAJOR 1 |
46 | #define DRIVER_MINOR 1 |
47 | |
48 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) |
49 | { |
50 | struct drm_exynos_file_private *file_priv; |
51 | int ret; |
52 | |
53 | file_priv = kzalloc(size: sizeof(*file_priv), GFP_KERNEL); |
54 | if (!file_priv) |
55 | return -ENOMEM; |
56 | |
57 | file->driver_priv = file_priv; |
58 | ret = g2d_open(drm_dev: dev, file); |
59 | if (ret) |
60 | goto err_file_priv_free; |
61 | |
62 | return ret; |
63 | |
64 | err_file_priv_free: |
65 | kfree(objp: file_priv); |
66 | file->driver_priv = NULL; |
67 | return ret; |
68 | } |
69 | |
70 | static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) |
71 | { |
72 | g2d_close(drm_dev: dev, file); |
73 | kfree(objp: file->driver_priv); |
74 | file->driver_priv = NULL; |
75 | } |
76 | |
77 | static const struct drm_ioctl_desc exynos_ioctls[] = { |
78 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, |
79 | DRM_RENDER_ALLOW), |
80 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP, exynos_drm_gem_map_ioctl, |
81 | DRM_RENDER_ALLOW), |
82 | DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl, |
83 | DRM_RENDER_ALLOW), |
84 | DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, vidi_connection_ioctl, |
85 | DRM_AUTH), |
86 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, exynos_g2d_get_ver_ioctl, |
87 | DRM_RENDER_ALLOW), |
88 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, exynos_g2d_set_cmdlist_ioctl, |
89 | DRM_RENDER_ALLOW), |
90 | DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, |
91 | DRM_RENDER_ALLOW), |
92 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_RESOURCES, |
93 | exynos_drm_ipp_get_res_ioctl, |
94 | DRM_RENDER_ALLOW), |
95 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_CAPS, exynos_drm_ipp_get_caps_ioctl, |
96 | DRM_RENDER_ALLOW), |
97 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_LIMITS, |
98 | exynos_drm_ipp_get_limits_ioctl, |
99 | DRM_RENDER_ALLOW), |
100 | DRM_IOCTL_DEF_DRV(EXYNOS_IPP_COMMIT, exynos_drm_ipp_commit_ioctl, |
101 | DRM_RENDER_ALLOW), |
102 | }; |
103 | |
104 | DEFINE_DRM_GEM_FOPS(exynos_drm_driver_fops); |
105 | |
106 | static const struct drm_driver exynos_drm_driver = { |
107 | .driver_features = DRIVER_MODESET | DRIVER_GEM |
108 | | DRIVER_ATOMIC | DRIVER_RENDER, |
109 | .open = exynos_drm_open, |
110 | .postclose = exynos_drm_postclose, |
111 | .dumb_create = exynos_drm_gem_dumb_create, |
112 | .gem_prime_import = exynos_drm_gem_prime_import, |
113 | .gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table, |
114 | .ioctls = exynos_ioctls, |
115 | .num_ioctls = ARRAY_SIZE(exynos_ioctls), |
116 | .fops = &exynos_drm_driver_fops, |
117 | .name = DRIVER_NAME, |
118 | .desc = DRIVER_DESC, |
119 | .date = DRIVER_DATE, |
120 | .major = DRIVER_MAJOR, |
121 | .minor = DRIVER_MINOR, |
122 | }; |
123 | |
124 | static int exynos_drm_suspend(struct device *dev) |
125 | { |
126 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
127 | |
128 | return drm_mode_config_helper_suspend(dev: drm_dev); |
129 | } |
130 | |
131 | static void exynos_drm_resume(struct device *dev) |
132 | { |
133 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
134 | |
135 | drm_mode_config_helper_resume(dev: drm_dev); |
136 | } |
137 | |
138 | static const struct dev_pm_ops exynos_drm_pm_ops = { |
139 | .prepare = exynos_drm_suspend, |
140 | .complete = exynos_drm_resume, |
141 | }; |
142 | |
143 | /* forward declaration */ |
144 | static struct platform_driver exynos_drm_platform_driver; |
145 | |
146 | struct exynos_drm_driver_info { |
147 | struct platform_driver *driver; |
148 | unsigned int flags; |
149 | }; |
150 | |
151 | #define DRM_COMPONENT_DRIVER BIT(0) /* supports component framework */ |
152 | #define DRM_VIRTUAL_DEVICE BIT(1) /* create virtual platform device */ |
153 | #define DRM_FIMC_DEVICE BIT(2) /* devices shared with V4L2 subsystem */ |
154 | |
155 | #define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL) |
156 | |
157 | /* |
158 | * Connector drivers should not be placed before associated crtc drivers, |
159 | * because connector requires pipe number of its crtc during initialization. |
160 | */ |
161 | static struct exynos_drm_driver_info exynos_drm_drivers[] = { |
162 | { |
163 | DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD), |
164 | DRM_COMPONENT_DRIVER |
165 | }, { |
166 | DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON), |
167 | DRM_COMPONENT_DRIVER |
168 | }, { |
169 | DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON), |
170 | DRM_COMPONENT_DRIVER |
171 | }, { |
172 | DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER), |
173 | DRM_COMPONENT_DRIVER |
174 | }, { |
175 | DRV_PTR(dp_driver, CONFIG_DRM_EXYNOS_DP), |
176 | DRM_COMPONENT_DRIVER |
177 | }, { |
178 | DRV_PTR(dsi_driver, CONFIG_DRM_EXYNOS_DSI), |
179 | DRM_COMPONENT_DRIVER |
180 | }, { |
181 | DRV_PTR(mic_driver, CONFIG_DRM_EXYNOS_MIC), |
182 | DRM_COMPONENT_DRIVER |
183 | }, { |
184 | DRV_PTR(hdmi_driver, CONFIG_DRM_EXYNOS_HDMI), |
185 | DRM_COMPONENT_DRIVER |
186 | }, { |
187 | DRV_PTR(vidi_driver, CONFIG_DRM_EXYNOS_VIDI), |
188 | DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE |
189 | }, { |
190 | DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D), |
191 | DRM_COMPONENT_DRIVER |
192 | }, { |
193 | DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC), |
194 | DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE, |
195 | }, { |
196 | DRV_PTR(rotator_driver, CONFIG_DRM_EXYNOS_ROTATOR), |
197 | DRM_COMPONENT_DRIVER |
198 | }, { |
199 | DRV_PTR(scaler_driver, CONFIG_DRM_EXYNOS_SCALER), |
200 | DRM_COMPONENT_DRIVER |
201 | }, { |
202 | DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC), |
203 | DRM_COMPONENT_DRIVER |
204 | }, { |
205 | &exynos_drm_platform_driver, |
206 | DRM_VIRTUAL_DEVICE |
207 | } |
208 | }; |
209 | |
210 | static struct component_match *exynos_drm_match_add(struct device *dev) |
211 | { |
212 | struct component_match *match = NULL; |
213 | int i; |
214 | |
215 | for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) { |
216 | struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; |
217 | struct device *p = NULL, *d; |
218 | |
219 | if (!info->driver || !(info->flags & DRM_COMPONENT_DRIVER)) |
220 | continue; |
221 | |
222 | while ((d = platform_find_device_by_driver(start: p, drv: &info->driver->driver))) { |
223 | put_device(dev: p); |
224 | |
225 | if (!(info->flags & DRM_FIMC_DEVICE) || |
226 | exynos_drm_check_fimc_device(dev: d) == 0) |
227 | component_match_add(parent: dev, matchptr: &match, compare: component_compare_dev, compare_data: d); |
228 | p = d; |
229 | } |
230 | put_device(dev: p); |
231 | } |
232 | |
233 | return match ?: ERR_PTR(error: -ENODEV); |
234 | } |
235 | |
236 | static int exynos_drm_bind(struct device *dev) |
237 | { |
238 | struct exynos_drm_private *private; |
239 | struct drm_encoder *encoder; |
240 | struct drm_device *drm; |
241 | unsigned int clone_mask; |
242 | int ret; |
243 | |
244 | drm = drm_dev_alloc(driver: &exynos_drm_driver, parent: dev); |
245 | if (IS_ERR(ptr: drm)) |
246 | return PTR_ERR(ptr: drm); |
247 | |
248 | private = kzalloc(size: sizeof(struct exynos_drm_private), GFP_KERNEL); |
249 | if (!private) { |
250 | ret = -ENOMEM; |
251 | goto err_free_drm; |
252 | } |
253 | |
254 | init_waitqueue_head(&private->wait); |
255 | spin_lock_init(&private->lock); |
256 | |
257 | dev_set_drvdata(dev, data: drm); |
258 | drm->dev_private = (void *)private; |
259 | |
260 | drm_mode_config_init(dev: drm); |
261 | |
262 | exynos_drm_mode_config_init(dev: drm); |
263 | |
264 | /* setup possible_clones. */ |
265 | clone_mask = 0; |
266 | list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) |
267 | clone_mask |= drm_encoder_mask(encoder); |
268 | |
269 | list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) |
270 | encoder->possible_clones = clone_mask; |
271 | |
272 | /* Try to bind all sub drivers. */ |
273 | ret = component_bind_all(parent: drm->dev, data: drm); |
274 | if (ret) |
275 | goto err_mode_config_cleanup; |
276 | |
277 | ret = drm_vblank_init(dev: drm, num_crtcs: drm->mode_config.num_crtc); |
278 | if (ret) |
279 | goto err_unbind_all; |
280 | |
281 | drm_mode_config_reset(dev: drm); |
282 | |
283 | /* init kms poll for handling hpd */ |
284 | drm_kms_helper_poll_init(dev: drm); |
285 | |
286 | /* register the DRM device */ |
287 | ret = drm_dev_register(dev: drm, flags: 0); |
288 | if (ret < 0) |
289 | goto err_cleanup_poll; |
290 | |
291 | exynos_drm_fbdev_setup(dev: drm); |
292 | |
293 | return 0; |
294 | |
295 | err_cleanup_poll: |
296 | drm_kms_helper_poll_fini(dev: drm); |
297 | err_unbind_all: |
298 | component_unbind_all(parent: drm->dev, data: drm); |
299 | err_mode_config_cleanup: |
300 | drm_mode_config_cleanup(dev: drm); |
301 | exynos_drm_cleanup_dma(drm); |
302 | kfree(objp: private); |
303 | dev_set_drvdata(dev, NULL); |
304 | err_free_drm: |
305 | drm_dev_put(dev: drm); |
306 | |
307 | return ret; |
308 | } |
309 | |
310 | static void exynos_drm_unbind(struct device *dev) |
311 | { |
312 | struct drm_device *drm = dev_get_drvdata(dev); |
313 | |
314 | drm_dev_unregister(dev: drm); |
315 | |
316 | drm_kms_helper_poll_fini(dev: drm); |
317 | drm_atomic_helper_shutdown(dev: drm); |
318 | |
319 | component_unbind_all(parent: drm->dev, data: drm); |
320 | drm_mode_config_cleanup(dev: drm); |
321 | exynos_drm_cleanup_dma(drm); |
322 | |
323 | kfree(objp: drm->dev_private); |
324 | drm->dev_private = NULL; |
325 | dev_set_drvdata(dev, NULL); |
326 | |
327 | drm_dev_put(dev: drm); |
328 | } |
329 | |
330 | static const struct component_master_ops exynos_drm_ops = { |
331 | .bind = exynos_drm_bind, |
332 | .unbind = exynos_drm_unbind, |
333 | }; |
334 | |
335 | static int exynos_drm_platform_probe(struct platform_device *pdev) |
336 | { |
337 | struct component_match *match; |
338 | |
339 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); |
340 | |
341 | match = exynos_drm_match_add(dev: &pdev->dev); |
342 | if (IS_ERR(ptr: match)) |
343 | return PTR_ERR(ptr: match); |
344 | |
345 | return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, |
346 | match); |
347 | } |
348 | |
349 | static void exynos_drm_platform_remove(struct platform_device *pdev) |
350 | { |
351 | component_master_del(&pdev->dev, &exynos_drm_ops); |
352 | } |
353 | |
354 | static void exynos_drm_platform_shutdown(struct platform_device *pdev) |
355 | { |
356 | struct drm_device *drm = platform_get_drvdata(pdev); |
357 | |
358 | if (drm) |
359 | drm_atomic_helper_shutdown(dev: drm); |
360 | } |
361 | |
362 | static struct platform_driver exynos_drm_platform_driver = { |
363 | .probe = exynos_drm_platform_probe, |
364 | .remove_new = exynos_drm_platform_remove, |
365 | .shutdown = exynos_drm_platform_shutdown, |
366 | .driver = { |
367 | .name = "exynos-drm" , |
368 | .pm = &exynos_drm_pm_ops, |
369 | }, |
370 | }; |
371 | |
372 | static void exynos_drm_unregister_devices(void) |
373 | { |
374 | int i; |
375 | |
376 | for (i = ARRAY_SIZE(exynos_drm_drivers) - 1; i >= 0; --i) { |
377 | struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; |
378 | struct device *dev; |
379 | |
380 | if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE)) |
381 | continue; |
382 | |
383 | while ((dev = platform_find_device_by_driver(NULL, |
384 | drv: &info->driver->driver))) { |
385 | put_device(dev); |
386 | platform_device_unregister(to_platform_device(dev)); |
387 | } |
388 | } |
389 | } |
390 | |
391 | static int exynos_drm_register_devices(void) |
392 | { |
393 | struct platform_device *pdev; |
394 | int i; |
395 | |
396 | for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) { |
397 | struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; |
398 | |
399 | if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE)) |
400 | continue; |
401 | |
402 | pdev = platform_device_register_simple( |
403 | name: info->driver->driver.name, id: -1, NULL, num: 0); |
404 | if (IS_ERR(ptr: pdev)) |
405 | goto fail; |
406 | } |
407 | |
408 | return 0; |
409 | fail: |
410 | exynos_drm_unregister_devices(); |
411 | return PTR_ERR(ptr: pdev); |
412 | } |
413 | |
414 | static void exynos_drm_unregister_drivers(void) |
415 | { |
416 | int i; |
417 | |
418 | for (i = ARRAY_SIZE(exynos_drm_drivers) - 1; i >= 0; --i) { |
419 | struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; |
420 | |
421 | if (!info->driver) |
422 | continue; |
423 | |
424 | platform_driver_unregister(info->driver); |
425 | } |
426 | } |
427 | |
428 | static int exynos_drm_register_drivers(void) |
429 | { |
430 | int i, ret; |
431 | |
432 | for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) { |
433 | struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; |
434 | |
435 | if (!info->driver) |
436 | continue; |
437 | |
438 | ret = platform_driver_register(info->driver); |
439 | if (ret) |
440 | goto fail; |
441 | } |
442 | return 0; |
443 | fail: |
444 | exynos_drm_unregister_drivers(); |
445 | return ret; |
446 | } |
447 | |
448 | static int exynos_drm_init(void) |
449 | { |
450 | int ret; |
451 | |
452 | if (drm_firmware_drivers_only()) |
453 | return -ENODEV; |
454 | |
455 | ret = exynos_drm_register_devices(); |
456 | if (ret) |
457 | return ret; |
458 | |
459 | ret = exynos_drm_register_drivers(); |
460 | if (ret) |
461 | goto err_unregister_pdevs; |
462 | |
463 | return 0; |
464 | |
465 | err_unregister_pdevs: |
466 | exynos_drm_unregister_devices(); |
467 | |
468 | return ret; |
469 | } |
470 | |
471 | static void exynos_drm_exit(void) |
472 | { |
473 | exynos_drm_unregister_drivers(); |
474 | exynos_drm_unregister_devices(); |
475 | } |
476 | |
477 | module_init(exynos_drm_init); |
478 | module_exit(exynos_drm_exit); |
479 | |
480 | MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>" ); |
481 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>" ); |
482 | MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>" ); |
483 | MODULE_DESCRIPTION("Samsung SoC DRM Driver" ); |
484 | MODULE_LICENSE("GPL" ); |
485 | |