1 // SPDX-License-Identifier: GPL-2.0-only
3 * Hisilicon Kirin SoCs drm master driver
5 * Copyright (c) 2016 Linaro Limited.
6 * Copyright (c) 2014-2016 HiSilicon Limited.
9 * Xinliang Liu <z.liuxinliang@hisilicon.com>
10 * Xinliang Liu <xinliang.liu@linaro.org>
11 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
14 #include <linux/component.h>
15 #include <linux/module.h>
17 #include <linux/of_graph.h>
18 #include <linux/platform_device.h>
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_client_setup.h>
22 #include <drm/drm_drv.h>
23 #include <drm/drm_gem_dma_helper.h>
24 #include <drm/drm_gem_framebuffer_helper.h>
25 #include <drm/drm_module.h>
26 #include <drm/drm_of.h>
27 #include <drm/drm_probe_helper.h>
28 #include <drm/drm_vblank.h>
30 #include "kirin_drm_drv.h"
32 #define KIRIN_MAX_PLANE 2
34 struct kirin_drm_private
{
35 struct kirin_crtc crtc
;
36 struct kirin_plane planes
[KIRIN_MAX_PLANE
];
40 static int kirin_drm_crtc_init(struct drm_device
*dev
, struct drm_crtc
*crtc
,
41 struct drm_plane
*plane
,
42 const struct kirin_drm_data
*driver_data
)
44 struct device_node
*port
;
47 /* set crtc port so that
48 * drm_of_find_possible_crtcs call works
50 port
= of_get_child_by_name(dev
->dev
->of_node
, "port");
52 DRM_ERROR("no port node found in %pOF\n", dev
->dev
->of_node
);
58 ret
= drm_crtc_init_with_planes(dev
, crtc
, plane
, NULL
,
59 driver_data
->crtc_funcs
, NULL
);
61 DRM_ERROR("failed to init crtc.\n");
65 drm_crtc_helper_add(crtc
, driver_data
->crtc_helper_funcs
);
70 static int kirin_drm_plane_init(struct drm_device
*dev
, struct drm_plane
*plane
,
71 enum drm_plane_type type
,
72 const struct kirin_drm_data
*data
)
76 ret
= drm_universal_plane_init(dev
, plane
, 1, data
->plane_funcs
,
77 data
->channel_formats
,
78 data
->channel_formats_cnt
,
81 DRM_ERROR("fail to init plane, ch=%d\n", 0);
85 drm_plane_helper_add(plane
, data
->plane_helper_funcs
);
90 static void kirin_drm_private_cleanup(struct drm_device
*dev
)
92 struct kirin_drm_private
*kirin_priv
= dev
->dev_private
;
93 struct kirin_drm_data
*data
;
95 data
= (struct kirin_drm_data
*)of_device_get_match_data(dev
->dev
);
96 if (data
->cleanup_hw_ctx
)
97 data
->cleanup_hw_ctx(kirin_priv
->hw_ctx
);
99 devm_kfree(dev
->dev
, kirin_priv
);
100 dev
->dev_private
= NULL
;
103 static int kirin_drm_private_init(struct drm_device
*dev
,
104 const struct kirin_drm_data
*driver_data
)
106 struct platform_device
*pdev
= to_platform_device(dev
->dev
);
107 struct kirin_drm_private
*kirin_priv
;
108 struct drm_plane
*prim_plane
;
109 enum drm_plane_type type
;
114 kirin_priv
= devm_kzalloc(dev
->dev
, sizeof(*kirin_priv
), GFP_KERNEL
);
116 DRM_ERROR("failed to alloc kirin_drm_private\n");
120 ctx
= driver_data
->alloc_hw_ctx(pdev
, &kirin_priv
->crtc
.base
);
122 DRM_ERROR("failed to initialize kirin_priv hw ctx\n");
125 kirin_priv
->hw_ctx
= ctx
;
129 * TODO: Now only support primary plane, overlay planes
132 for (ch
= 0; ch
< driver_data
->num_planes
; ch
++) {
133 if (ch
== driver_data
->prim_plane
)
134 type
= DRM_PLANE_TYPE_PRIMARY
;
136 type
= DRM_PLANE_TYPE_OVERLAY
;
137 ret
= kirin_drm_plane_init(dev
, &kirin_priv
->planes
[ch
].base
,
141 kirin_priv
->planes
[ch
].ch
= ch
;
142 kirin_priv
->planes
[ch
].hw_ctx
= ctx
;
146 prim_plane
= &kirin_priv
->planes
[driver_data
->prim_plane
].base
;
147 ret
= kirin_drm_crtc_init(dev
, &kirin_priv
->crtc
.base
,
148 prim_plane
, driver_data
);
151 kirin_priv
->crtc
.hw_ctx
= ctx
;
152 dev
->dev_private
= kirin_priv
;
157 static int kirin_drm_kms_init(struct drm_device
*dev
,
158 const struct kirin_drm_data
*driver_data
)
162 /* dev->mode_config initialization */
163 drm_mode_config_init(dev
);
164 dev
->mode_config
.min_width
= 0;
165 dev
->mode_config
.min_height
= 0;
166 dev
->mode_config
.max_width
= driver_data
->config_max_width
;
167 dev
->mode_config
.max_height
= driver_data
->config_max_width
;
168 dev
->mode_config
.funcs
= driver_data
->mode_config_funcs
;
170 /* display controller init */
171 ret
= kirin_drm_private_init(dev
, driver_data
);
173 goto err_mode_config_cleanup
;
175 /* bind and init sub drivers */
176 ret
= component_bind_all(dev
->dev
, dev
);
178 DRM_ERROR("failed to bind all component.\n");
179 goto err_private_cleanup
;
183 ret
= drm_vblank_init(dev
, dev
->mode_config
.num_crtc
);
185 DRM_ERROR("failed to initialize vblank.\n");
189 /* reset all the states of crtc/plane/encoder/connector */
190 drm_mode_config_reset(dev
);
192 /* init kms poll for handling hpd */
193 drm_kms_helper_poll_init(dev
);
198 component_unbind_all(dev
->dev
, dev
);
200 kirin_drm_private_cleanup(dev
);
201 err_mode_config_cleanup
:
202 drm_mode_config_cleanup(dev
);
206 static int kirin_drm_kms_cleanup(struct drm_device
*dev
)
208 drm_kms_helper_poll_fini(dev
);
209 drm_atomic_helper_shutdown(dev
);
210 kirin_drm_private_cleanup(dev
);
211 drm_mode_config_cleanup(dev
);
216 static int kirin_drm_bind(struct device
*dev
)
218 struct kirin_drm_data
*driver_data
;
219 struct drm_device
*drm_dev
;
222 driver_data
= (struct kirin_drm_data
*)of_device_get_match_data(dev
);
226 drm_dev
= drm_dev_alloc(driver_data
->driver
, dev
);
228 return PTR_ERR(drm_dev
);
229 dev_set_drvdata(dev
, drm_dev
);
231 /* display controller init */
232 ret
= kirin_drm_kms_init(drm_dev
, driver_data
);
234 goto err_drm_dev_put
;
236 ret
= drm_dev_register(drm_dev
, 0);
238 goto err_kms_cleanup
;
240 drm_client_setup(drm_dev
, NULL
);
245 kirin_drm_kms_cleanup(drm_dev
);
247 drm_dev_put(drm_dev
);
248 dev_set_drvdata(dev
, NULL
);
253 static void kirin_drm_unbind(struct device
*dev
)
255 struct drm_device
*drm_dev
= dev_get_drvdata(dev
);
257 drm_dev_unregister(drm_dev
);
258 kirin_drm_kms_cleanup(drm_dev
);
259 drm_dev_put(drm_dev
);
260 dev_set_drvdata(dev
, NULL
);
263 static const struct component_master_ops kirin_drm_ops
= {
264 .bind
= kirin_drm_bind
,
265 .unbind
= kirin_drm_unbind
,
268 static int kirin_drm_platform_probe(struct platform_device
*pdev
)
270 struct device
*dev
= &pdev
->dev
;
271 struct device_node
*np
= dev
->of_node
;
272 struct component_match
*match
= NULL
;
273 struct device_node
*remote
;
275 remote
= of_graph_get_remote_node(np
, 0, 0);
279 drm_of_component_match_add(dev
, &match
, component_compare_of
, remote
);
282 return component_master_add_with_match(dev
, &kirin_drm_ops
, match
);
285 static void kirin_drm_platform_remove(struct platform_device
*pdev
)
287 component_master_del(&pdev
->dev
, &kirin_drm_ops
);
290 static void kirin_drm_platform_shutdown(struct platform_device
*pdev
)
292 drm_atomic_helper_shutdown(platform_get_drvdata(pdev
));
295 static const struct of_device_id kirin_drm_dt_ids
[] = {
296 { .compatible
= "hisilicon,hi6220-ade",
297 .data
= &ade_driver_data
,
301 MODULE_DEVICE_TABLE(of
, kirin_drm_dt_ids
);
303 static struct platform_driver kirin_drm_platform_driver
= {
304 .probe
= kirin_drm_platform_probe
,
305 .remove
= kirin_drm_platform_remove
,
306 .shutdown
= kirin_drm_platform_shutdown
,
309 .of_match_table
= kirin_drm_dt_ids
,
313 drm_module_platform_driver(kirin_drm_platform_driver
);
315 MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
316 MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
317 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
318 MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
319 MODULE_LICENSE("GPL v2");