blob: 941f35233b1fe01ae1ae36061dd3747ce89f23d4 [file] [log] [blame]
Mark Yao2048e322014-08-22 18:36:26 +08001/*
2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Author:Mark Yao <mark.yao@rock-chips.com>
4 *
5 * based on exynos_drm_drv.c
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
Mark Yao2048e322014-08-22 18:36:26 +080017#include <drm/drmP.h>
18#include <drm/drm_crtc_helper.h>
19#include <drm/drm_fb_helper.h>
Daniel Vetter80f67cd2016-05-30 19:53:12 +020020#include <drm/drm_gem_cma_helper.h>
Russell King97ac0e42016-10-19 11:28:27 +010021#include <drm/drm_of.h>
Mark Yao2048e322014-08-22 18:36:26 +080022#include <linux/dma-mapping.h>
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080023#include <linux/dma-iommu.h>
Mark Yao2048e322014-08-22 18:36:26 +080024#include <linux/pm_runtime.h>
Paul Gortmaker00fe6142015-05-01 20:02:30 -040025#include <linux/module.h>
Mark Yao2048e322014-08-22 18:36:26 +080026#include <linux/of_graph.h>
Heiko Stuebner3880f622018-08-30 23:12:05 +020027#include <linux/of_platform.h>
Mark Yao2048e322014-08-22 18:36:26 +080028#include <linux/component.h>
Tomeu Vizoso5a587382016-06-06 16:53:32 +020029#include <linux/console.h>
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080030#include <linux/iommu.h>
Mark Yao2048e322014-08-22 18:36:26 +080031
32#include "rockchip_drm_drv.h"
33#include "rockchip_drm_fb.h"
34#include "rockchip_drm_fbdev.h"
35#include "rockchip_drm_gem.h"
36
37#define DRIVER_NAME "rockchip"
38#define DRIVER_DESC "RockChip Soc DRM"
39#define DRIVER_DATE "20140818"
40#define DRIVER_MAJOR 1
41#define DRIVER_MINOR 0
42
Mark Yao2d90d472016-04-19 10:13:27 +080043static bool is_support_iommu = true;
Tomeu Vizosof7069742016-06-10 13:14:13 +020044static struct drm_driver rockchip_drm_driver;
Mark Yao2d90d472016-04-19 10:13:27 +080045
Mark Yao2048e322014-08-22 18:36:26 +080046/*
47 * Attach a (component) device to the shared drm dma mapping from master drm
48 * device. This is used by the VOPs to map GEM buffers to a common DMA
49 * mapping.
50 */
51int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
52 struct device *dev)
53{
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080054 struct rockchip_drm_private *private = drm_dev->dev_private;
Mark Yao2048e322014-08-22 18:36:26 +080055 int ret;
56
Mark Yao2d90d472016-04-19 10:13:27 +080057 if (!is_support_iommu)
58 return 0;
59
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080060 ret = iommu_attach_device(private->domain, dev);
61 if (ret) {
Haneen Mohammedd8dd6802017-09-15 02:36:03 -060062 DRM_DEV_ERROR(dev, "Failed to attach iommu device\n");
Mark Yao2048e322014-08-22 18:36:26 +080063 return ret;
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080064 }
Mark Yao2048e322014-08-22 18:36:26 +080065
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080066 return 0;
Mark Yao2048e322014-08-22 18:36:26 +080067}
Mark Yao2048e322014-08-22 18:36:26 +080068
69void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
70 struct device *dev)
71{
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080072 struct rockchip_drm_private *private = drm_dev->dev_private;
73 struct iommu_domain *domain = private->domain;
74
Mark Yao2d90d472016-04-19 10:13:27 +080075 if (!is_support_iommu)
76 return;
77
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080078 iommu_detach_device(domain, dev);
Mark Yao2048e322014-08-22 18:36:26 +080079}
Mark Yao2048e322014-08-22 18:36:26 +080080
Shunqian Zheng1aa5ca62016-06-24 10:13:32 +080081static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
82{
83 struct rockchip_drm_private *private = drm_dev->dev_private;
84 struct iommu_domain_geometry *geometry;
85 u64 start, end;
86
87 if (!is_support_iommu)
88 return 0;
89
90 private->domain = iommu_domain_alloc(&platform_bus_type);
91 if (!private->domain)
92 return -ENOMEM;
93
94 geometry = &private->domain->geometry;
95 start = geometry->aperture_start;
96 end = geometry->aperture_end;
97
98 DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n",
99 start, end);
100 drm_mm_init(&private->mm, start, end - start + 1);
101 mutex_init(&private->mm_lock);
102
103 return 0;
104}
105
106static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
107{
108 struct rockchip_drm_private *private = drm_dev->dev_private;
109
110 if (!is_support_iommu)
111 return;
112
113 drm_mm_takedown(&private->mm);
114 iommu_domain_free(private->domain);
Mark Yao2048e322014-08-22 18:36:26 +0800115}
116
Tomeu Vizosof7069742016-06-10 13:14:13 +0200117static int rockchip_drm_bind(struct device *dev)
Mark Yao2048e322014-08-22 18:36:26 +0800118{
Tomeu Vizosof7069742016-06-10 13:14:13 +0200119 struct drm_device *drm_dev;
Mark Yao2048e322014-08-22 18:36:26 +0800120 struct rockchip_drm_private *private;
Mark Yao2048e322014-08-22 18:36:26 +0800121 int ret;
122
Tomeu Vizosof7069742016-06-10 13:14:13 +0200123 drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
Tom Gundersen0f288602016-09-21 16:59:19 +0200124 if (IS_ERR(drm_dev))
125 return PTR_ERR(drm_dev);
Mark Yao2048e322014-08-22 18:36:26 +0800126
Tomeu Vizosof7069742016-06-10 13:14:13 +0200127 dev_set_drvdata(dev, drm_dev);
128
129 private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
130 if (!private) {
131 ret = -ENOMEM;
Tomasz Figa9127f992016-06-21 13:27:34 +0900132 goto err_free;
Tomeu Vizosof7069742016-06-10 13:14:13 +0200133 }
134
Mark Yao2048e322014-08-22 18:36:26 +0800135 drm_dev->dev_private = private;
136
Yakir Yang5182c1a2016-07-24 14:57:44 +0800137 INIT_LIST_HEAD(&private->psr_list);
Sean Paul60beecc2018-03-05 23:22:54 +0100138 mutex_init(&private->psr_list_lock);
Yakir Yang5182c1a2016-07-24 14:57:44 +0800139
Jeffy Chenccea9192017-04-06 20:31:23 +0800140 ret = rockchip_drm_init_iommu(drm_dev);
141 if (ret)
142 goto err_free;
143
Mark Yao2048e322014-08-22 18:36:26 +0800144 drm_mode_config_init(drm_dev);
145
146 rockchip_drm_mode_config_init(drm_dev);
147
Mark Yao2048e322014-08-22 18:36:26 +0800148 /* Try to bind all sub drivers. */
149 ret = component_bind_all(dev, drm_dev);
150 if (ret)
Jeffy Chenccea9192017-04-06 20:31:23 +0800151 goto err_mode_config_cleanup;
Mark Yao2048e322014-08-22 18:36:26 +0800152
Jeffy Chenccea9192017-04-06 20:31:23 +0800153 ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
154 if (ret)
155 goto err_unbind_all;
156
157 drm_mode_config_reset(drm_dev);
Mark Yao2048e322014-08-22 18:36:26 +0800158
159 /*
160 * enable drm irq mode.
161 * - with irq_enabled = true, we can use the vblank feature.
162 */
163 drm_dev->irq_enabled = true;
164
Mark yao8415ab52017-08-01 16:11:43 +0800165 ret = rockchip_drm_fbdev_init(drm_dev);
166 if (ret)
167 goto err_unbind_all;
168
Jeffy Chenccea9192017-04-06 20:31:23 +0800169 /* init kms poll for handling hpd */
170 drm_kms_helper_poll_init(drm_dev);
Mark Yao63ebb9f2015-11-30 18:22:42 +0800171
Mark yao8415ab52017-08-01 16:11:43 +0800172 ret = drm_dev_register(drm_dev, 0);
Mark Yao2048e322014-08-22 18:36:26 +0800173 if (ret)
Jeffy Chenccea9192017-04-06 20:31:23 +0800174 goto err_kms_helper_poll_fini;
Mark Yao2048e322014-08-22 18:36:26 +0800175
176 return 0;
Mark Yao2048e322014-08-22 18:36:26 +0800177err_kms_helper_poll_fini:
178 drm_kms_helper_poll_fini(drm_dev);
Mark yao8415ab52017-08-01 16:11:43 +0800179 rockchip_drm_fbdev_fini(drm_dev);
Jeffy Chenccea9192017-04-06 20:31:23 +0800180err_unbind_all:
Mark Yao2048e322014-08-22 18:36:26 +0800181 component_unbind_all(dev, drm_dev);
Jeffy Chenccea9192017-04-06 20:31:23 +0800182err_mode_config_cleanup:
Mark Yao2048e322014-08-22 18:36:26 +0800183 drm_mode_config_cleanup(drm_dev);
Jeffy Chenccea9192017-04-06 20:31:23 +0800184 rockchip_iommu_cleanup(drm_dev);
Tomeu Vizosof7069742016-06-10 13:14:13 +0200185err_free:
Jeffy Chenccea9192017-04-06 20:31:23 +0800186 drm_dev->dev_private = NULL;
187 dev_set_drvdata(dev, NULL);
Thomas Zimmermann574e0fb2018-07-17 13:09:27 +0200188 drm_dev_put(drm_dev);
Mark Yao2048e322014-08-22 18:36:26 +0800189 return ret;
190}
191
Tomeu Vizosof7069742016-06-10 13:14:13 +0200192static void rockchip_drm_unbind(struct device *dev)
Mark Yao2048e322014-08-22 18:36:26 +0800193{
Tomeu Vizosof7069742016-06-10 13:14:13 +0200194 struct drm_device *drm_dev = dev_get_drvdata(dev);
Mark Yao2048e322014-08-22 18:36:26 +0800195
Tomeu Vizosof7069742016-06-10 13:14:13 +0200196 drm_dev_unregister(drm_dev);
Jeffy Chenccea9192017-04-06 20:31:23 +0800197
198 rockchip_drm_fbdev_fini(drm_dev);
199 drm_kms_helper_poll_fini(drm_dev);
200
Jeffy Chenc1bb8182017-04-06 20:31:24 +0800201 drm_atomic_helper_shutdown(drm_dev);
Jeffy Chenccea9192017-04-06 20:31:23 +0800202 component_unbind_all(dev, drm_dev);
203 drm_mode_config_cleanup(drm_dev);
204 rockchip_iommu_cleanup(drm_dev);
205
206 drm_dev->dev_private = NULL;
Tomeu Vizosof7069742016-06-10 13:14:13 +0200207 dev_set_drvdata(dev, NULL);
Thomas Zimmermann574e0fb2018-07-17 13:09:27 +0200208 drm_dev_put(drm_dev);
Mark Yao2048e322014-08-22 18:36:26 +0800209}
210
Mark Yao2048e322014-08-22 18:36:26 +0800211static const struct file_operations rockchip_drm_driver_fops = {
212 .owner = THIS_MODULE,
213 .open = drm_open,
214 .mmap = rockchip_gem_mmap,
215 .poll = drm_poll,
216 .read = drm_read,
217 .unlocked_ioctl = drm_ioctl,
Mark Yao2048e322014-08-22 18:36:26 +0800218 .compat_ioctl = drm_compat_ioctl,
Mark Yao2048e322014-08-22 18:36:26 +0800219 .release = drm_release,
220};
221
Mark Yao2048e322014-08-22 18:36:26 +0800222static struct drm_driver rockchip_drm_driver = {
Mark Yao63ebb9f2015-11-30 18:22:42 +0800223 .driver_features = DRIVER_MODESET | DRIVER_GEM |
224 DRIVER_PRIME | DRIVER_ATOMIC,
Noralf Trønnes33e9d032017-12-05 19:25:03 +0100225 .lastclose = drm_fb_helper_lastclose,
Daniel Vetter80f67cd2016-05-30 19:53:12 +0200226 .gem_vm_ops = &drm_gem_cma_vm_ops,
Daniel Vetterc2466ac2016-05-30 19:53:03 +0200227 .gem_free_object_unlocked = rockchip_gem_free_object,
Mark Yao2048e322014-08-22 18:36:26 +0800228 .dumb_create = rockchip_gem_dumb_create,
Mark Yao2048e322014-08-22 18:36:26 +0800229 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
230 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
231 .gem_prime_import = drm_gem_prime_import,
232 .gem_prime_export = drm_gem_prime_export,
233 .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table,
Haixia Shi6fd0bfe2018-01-30 21:28:32 +0100234 .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table,
Mark Yao2048e322014-08-22 18:36:26 +0800235 .gem_prime_vmap = rockchip_gem_prime_vmap,
236 .gem_prime_vunmap = rockchip_gem_prime_vunmap,
237 .gem_prime_mmap = rockchip_gem_mmap_buf,
238 .fops = &rockchip_drm_driver_fops,
239 .name = DRIVER_NAME,
240 .desc = DRIVER_DESC,
241 .date = DRIVER_DATE,
242 .major = DRIVER_MAJOR,
243 .minor = DRIVER_MINOR,
244};
245
246#ifdef CONFIG_PM_SLEEP
247static int rockchip_drm_sys_suspend(struct device *dev)
248{
249 struct drm_device *drm = dev_get_drvdata(dev);
Jeffy Chen0fa375e2017-08-09 18:41:03 +0800250
Souptick Joardere7941cc2018-08-01 02:04:30 +0530251 return drm_mode_config_helper_suspend(drm);
Mark Yao2048e322014-08-22 18:36:26 +0800252}
253
254static int rockchip_drm_sys_resume(struct device *dev)
255{
256 struct drm_device *drm = dev_get_drvdata(dev);
Mark Yao2048e322014-08-22 18:36:26 +0800257
Souptick Joardere7941cc2018-08-01 02:04:30 +0530258 return drm_mode_config_helper_resume(drm);
Mark Yao2048e322014-08-22 18:36:26 +0800259}
260#endif
261
262static const struct dev_pm_ops rockchip_drm_pm_ops = {
263 SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend,
264 rockchip_drm_sys_resume)
265};
266
Jeffy Chen8820b682017-03-22 11:21:20 +0800267#define MAX_ROCKCHIP_SUB_DRIVERS 16
268static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS];
269static int num_rockchip_sub_drivers;
Mark Yao2048e322014-08-22 18:36:26 +0800270
Heiko Stuebner3880f622018-08-30 23:12:05 +0200271/*
272 * Check if a vop endpoint is leading to a rockchip subdriver or bridge.
273 * Should be called from the component bind stage of the drivers
274 * to ensure that all subdrivers are probed.
275 *
276 * @ep: endpoint of a rockchip vop
277 *
278 * returns true if subdriver, false if external bridge and -ENODEV
279 * if remote port does not contain a device.
280 */
281int rockchip_drm_endpoint_is_subdriver(struct device_node *ep)
282{
283 struct device_node *node = of_graph_get_remote_port_parent(ep);
284 struct platform_device *pdev;
285 struct device_driver *drv;
286 int i;
287
288 if (!node)
289 return -ENODEV;
290
291 /* status disabled will prevent creation of platform-devices */
292 pdev = of_find_device_by_node(node);
293 of_node_put(node);
294 if (!pdev)
295 return -ENODEV;
296
297 /*
298 * All rockchip subdrivers have probed at this point, so
299 * any device not having a driver now is an external bridge.
300 */
301 drv = pdev->dev.driver;
302 if (!drv) {
303 platform_device_put(pdev);
304 return false;
305 }
306
307 for (i = 0; i < num_rockchip_sub_drivers; i++) {
308 if (rockchip_sub_drivers[i] == to_platform_driver(drv)) {
309 platform_device_put(pdev);
310 return true;
311 }
312 }
313
314 platform_device_put(pdev);
315 return false;
316}
317
Jeffy Chen8820b682017-03-22 11:21:20 +0800318static int compare_dev(struct device *dev, void *data)
319{
320 return dev == (struct device *)data;
Mark Yao2048e322014-08-22 18:36:26 +0800321}
322
Jeffy Chen7d4e9812018-02-07 18:53:09 +0100323static void rockchip_drm_match_remove(struct device *dev)
324{
325 struct device_link *link;
326
327 list_for_each_entry(link, &dev->links.consumers, s_node)
328 device_link_del(link);
329}
330
Jeffy Chen8820b682017-03-22 11:21:20 +0800331static struct component_match *rockchip_drm_match_add(struct device *dev)
Mark Yao5bad7d22015-11-10 16:47:19 +0800332{
Jeffy Chen8820b682017-03-22 11:21:20 +0800333 struct component_match *match = NULL;
334 int i;
Mark Yao5bad7d22015-11-10 16:47:19 +0800335
Jeffy Chen8820b682017-03-22 11:21:20 +0800336 for (i = 0; i < num_rockchip_sub_drivers; i++) {
337 struct platform_driver *drv = rockchip_sub_drivers[i];
338 struct device *p = NULL, *d;
Mark Yao5bad7d22015-11-10 16:47:19 +0800339
Jeffy Chen8820b682017-03-22 11:21:20 +0800340 do {
341 d = bus_find_device(&platform_bus_type, p, &drv->driver,
342 (void *)platform_bus_type.match);
343 put_device(p);
344 p = d;
345
346 if (!d)
347 break;
Jeffy Chen7d4e9812018-02-07 18:53:09 +0100348
349 device_link_add(dev, d, DL_FLAG_STATELESS);
Jeffy Chen8820b682017-03-22 11:21:20 +0800350 component_match_add(dev, &match, compare_dev, d);
351 } while (true);
Mark Yao5bad7d22015-11-10 16:47:19 +0800352 }
Jeffy Chen8820b682017-03-22 11:21:20 +0800353
Jeffy Chen7d4e9812018-02-07 18:53:09 +0100354 if (IS_ERR(match))
355 rockchip_drm_match_remove(dev);
356
Jeffy Chen8820b682017-03-22 11:21:20 +0800357 return match ?: ERR_PTR(-ENODEV);
Mark Yao5bad7d22015-11-10 16:47:19 +0800358}
359
Mark Yao2048e322014-08-22 18:36:26 +0800360static const struct component_master_ops rockchip_drm_ops = {
361 .bind = rockchip_drm_bind,
362 .unbind = rockchip_drm_unbind,
363};
364
Jeffy Chen8820b682017-03-22 11:21:20 +0800365static int rockchip_drm_platform_of_probe(struct device *dev)
Mark Yao2048e322014-08-22 18:36:26 +0800366{
Mark Yao5bad7d22015-11-10 16:47:19 +0800367 struct device_node *np = dev->of_node;
368 struct device_node *port;
Jeffy Chen8820b682017-03-22 11:21:20 +0800369 bool found = false;
Mark Yao5bad7d22015-11-10 16:47:19 +0800370 int i;
Mark Yao2048e322014-08-22 18:36:26 +0800371
Mark Yao5bad7d22015-11-10 16:47:19 +0800372 if (!np)
Mark Yao2048e322014-08-22 18:36:26 +0800373 return -ENODEV;
Jeffy Chen8820b682017-03-22 11:21:20 +0800374
Mark Yao5bad7d22015-11-10 16:47:19 +0800375 for (i = 0;; i++) {
Mark Yao2d90d472016-04-19 10:13:27 +0800376 struct device_node *iommu;
377
Mark Yao5bad7d22015-11-10 16:47:19 +0800378 port = of_parse_phandle(np, "ports", i);
379 if (!port)
380 break;
Mark Yao2048e322014-08-22 18:36:26 +0800381
Mark Yao5bad7d22015-11-10 16:47:19 +0800382 if (!of_device_is_available(port->parent)) {
383 of_node_put(port);
384 continue;
385 }
386
Mark Yao2d90d472016-04-19 10:13:27 +0800387 iommu = of_parse_phandle(port->parent, "iommus", 0);
388 if (!iommu || !of_device_is_available(iommu->parent)) {
Haneen Mohammedd8dd6802017-09-15 02:36:03 -0600389 DRM_DEV_DEBUG(dev,
390 "no iommu attached for %pOF, using non-iommu buffers\n",
391 port->parent);
Mark Yao2d90d472016-04-19 10:13:27 +0800392 /*
393 * if there is a crtc not support iommu, force set all
394 * crtc use non-iommu buffer.
395 */
396 is_support_iommu = false;
397 }
398
Jeffy Chen8820b682017-03-22 11:21:20 +0800399 found = true;
400
Peter Chen6d5fa282016-07-05 10:04:48 +0800401 of_node_put(iommu);
Mark Yao5bad7d22015-11-10 16:47:19 +0800402 of_node_put(port);
403 }
404
405 if (i == 0) {
Haneen Mohammedd8dd6802017-09-15 02:36:03 -0600406 DRM_DEV_ERROR(dev, "missing 'ports' property\n");
Mark Yao5bad7d22015-11-10 16:47:19 +0800407 return -ENODEV;
408 }
409
Jeffy Chen8820b682017-03-22 11:21:20 +0800410 if (!found) {
Haneen Mohammedd8dd6802017-09-15 02:36:03 -0600411 DRM_DEV_ERROR(dev,
412 "No available vop found for display-subsystem.\n");
Mark Yao5bad7d22015-11-10 16:47:19 +0800413 return -ENODEV;
414 }
Mark Yao5bad7d22015-11-10 16:47:19 +0800415
Jeffy Chen8820b682017-03-22 11:21:20 +0800416 return 0;
417}
Mark Yao5bad7d22015-11-10 16:47:19 +0800418
Jeffy Chen8820b682017-03-22 11:21:20 +0800419static int rockchip_drm_platform_probe(struct platform_device *pdev)
420{
421 struct device *dev = &pdev->dev;
422 struct component_match *match = NULL;
423 int ret;
424
425 ret = rockchip_drm_platform_of_probe(dev);
426 if (ret)
427 return ret;
428
429 match = rockchip_drm_match_add(dev);
430 if (IS_ERR(match))
431 return PTR_ERR(match);
Mark Yao5bad7d22015-11-10 16:47:19 +0800432
Jeffy Chen7d4e9812018-02-07 18:53:09 +0100433 ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
434 if (ret < 0) {
435 rockchip_drm_match_remove(dev);
436 return ret;
437 }
438
439 return 0;
Mark Yao2048e322014-08-22 18:36:26 +0800440}
441
442static int rockchip_drm_platform_remove(struct platform_device *pdev)
443{
444 component_master_del(&pdev->dev, &rockchip_drm_ops);
445
Jeffy Chen7d4e9812018-02-07 18:53:09 +0100446 rockchip_drm_match_remove(&pdev->dev);
447
Mark Yao2048e322014-08-22 18:36:26 +0800448 return 0;
449}
450
Marc Zyngier7f3ef5d2018-08-05 13:48:07 +0100451static void rockchip_drm_platform_shutdown(struct platform_device *pdev)
452{
453 rockchip_drm_platform_remove(pdev);
454}
455
Mark Yao2048e322014-08-22 18:36:26 +0800456static const struct of_device_id rockchip_drm_dt_ids[] = {
457 { .compatible = "rockchip,display-subsystem", },
458 { /* sentinel */ },
459};
460MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids);
461
462static struct platform_driver rockchip_drm_platform_driver = {
463 .probe = rockchip_drm_platform_probe,
464 .remove = rockchip_drm_platform_remove,
Marc Zyngier7f3ef5d2018-08-05 13:48:07 +0100465 .shutdown = rockchip_drm_platform_shutdown,
Mark Yao2048e322014-08-22 18:36:26 +0800466 .driver = {
Mark Yao2048e322014-08-22 18:36:26 +0800467 .name = "rockchip-drm",
468 .of_match_table = rockchip_drm_dt_ids,
469 .pm = &rockchip_drm_pm_ops,
470 },
471};
472
Jeffy Chen8820b682017-03-22 11:21:20 +0800473#define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \
474 if (IS_ENABLED(cond) && \
475 !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \
476 rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \
477}
478
479static int __init rockchip_drm_init(void)
480{
481 int ret;
482
483 num_rockchip_sub_drivers = 0;
484 ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP);
Sandy Huang34cc0aa2017-09-02 19:28:54 +0800485 ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
486 CONFIG_ROCKCHIP_LVDS);
Jeffy Chen8820b682017-03-22 11:21:20 +0800487 ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
488 CONFIG_ROCKCHIP_ANALOGIX_DP);
489 ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
490 ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
491 CONFIG_ROCKCHIP_DW_HDMI);
492 ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver,
493 CONFIG_ROCKCHIP_DW_MIPI_DSI);
494 ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
495
496 ret = platform_register_drivers(rockchip_sub_drivers,
497 num_rockchip_sub_drivers);
498 if (ret)
499 return ret;
500
501 ret = platform_driver_register(&rockchip_drm_platform_driver);
502 if (ret)
503 goto err_unreg_drivers;
504
505 return 0;
506
507err_unreg_drivers:
508 platform_unregister_drivers(rockchip_sub_drivers,
509 num_rockchip_sub_drivers);
510 return ret;
511}
512
513static void __exit rockchip_drm_fini(void)
514{
515 platform_driver_unregister(&rockchip_drm_platform_driver);
516
517 platform_unregister_drivers(rockchip_sub_drivers,
518 num_rockchip_sub_drivers);
519}
520
521module_init(rockchip_drm_init);
522module_exit(rockchip_drm_fini);
Mark Yao2048e322014-08-22 18:36:26 +0800523
524MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
525MODULE_DESCRIPTION("ROCKCHIP DRM Driver");
526MODULE_LICENSE("GPL v2");