Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Hisilicon Kirin SoCs drm master driver
  4 *
  5 * Copyright (c) 2016 Linaro Limited.
  6 * Copyright (c) 2014-2016 HiSilicon Limited.
  7 *
  8 * Author:
  9 *	Xinliang Liu <z.liuxinliang@hisilicon.com>
 10 *	Xinliang Liu <xinliang.liu@linaro.org>
 11 *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
 12 */
 13
 14#include <linux/component.h>
 15#include <linux/module.h>
 16#include <linux/of.h>
 17#include <linux/of_graph.h>
 18#include <linux/platform_device.h>
 19
 20#include <drm/drm_atomic_helper.h>
 21#include <drm/drm_drv.h>
 22#include <drm/drm_fbdev_generic.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>
 29
 30#include "kirin_drm_drv.h"
 31
 32#define KIRIN_MAX_PLANE	2
 33
 34struct kirin_drm_private {
 35	struct kirin_crtc crtc;
 36	struct kirin_plane planes[KIRIN_MAX_PLANE];
 37	void *hw_ctx;
 38};
 39
 40static 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)
 43{
 44	struct device_node *port;
 45	int ret;
 46
 47	/* set crtc port so that
 48	 * drm_of_find_possible_crtcs call works
 49	 */
 50	port = of_get_child_by_name(dev->dev->of_node, "port");
 51	if (!port) {
 52		DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node);
 53		return -EINVAL;
 54	}
 55	of_node_put(port);
 56	crtc->port = port;
 57
 58	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
 59					driver_data->crtc_funcs, NULL);
 60	if (ret) {
 61		DRM_ERROR("failed to init crtc.\n");
 62		return ret;
 63	}
 64
 65	drm_crtc_helper_add(crtc, driver_data->crtc_helper_funcs);
 66
 67	return 0;
 68}
 69
 70static 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)
 73{
 74	int ret = 0;
 75
 76	ret = drm_universal_plane_init(dev, plane, 1, data->plane_funcs,
 77				       data->channel_formats,
 78				       data->channel_formats_cnt,
 79				       NULL, type, NULL);
 80	if (ret) {
 81		DRM_ERROR("fail to init plane, ch=%d\n", 0);
 82		return ret;
 83	}
 84
 85	drm_plane_helper_add(plane, data->plane_helper_funcs);
 86
 87	return 0;
 88}
 89
 90static void kirin_drm_private_cleanup(struct drm_device *dev)
 91{
 92	struct kirin_drm_private *kirin_priv = dev->dev_private;
 93	struct kirin_drm_data *data;
 94
 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);
 98
 99	devm_kfree(dev->dev, kirin_priv);
100	dev->dev_private = NULL;
101}
102
103static int kirin_drm_private_init(struct drm_device *dev,
104				  const struct kirin_drm_data *driver_data)
105{
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;
110	void *ctx;
111	int ret;
112	u32 ch;
113
114	kirin_priv = devm_kzalloc(dev->dev, sizeof(*kirin_priv), GFP_KERNEL);
115	if (!kirin_priv) {
116		DRM_ERROR("failed to alloc kirin_drm_private\n");
117		return -ENOMEM;
118	}
119
120	ctx = driver_data->alloc_hw_ctx(pdev, &kirin_priv->crtc.base);
121	if (IS_ERR(ctx)) {
122		DRM_ERROR("failed to initialize kirin_priv hw ctx\n");
123		return -EINVAL;
124	}
125	kirin_priv->hw_ctx = ctx;
126
127	/*
128	 * plane init
129	 * TODO: Now only support primary plane, overlay planes
130	 * need to do.
131	 */
132	for (ch = 0; ch < driver_data->num_planes; ch++) {
133		if (ch == driver_data->prim_plane)
134			type = DRM_PLANE_TYPE_PRIMARY;
135		else
136			type = DRM_PLANE_TYPE_OVERLAY;
137		ret = kirin_drm_plane_init(dev, &kirin_priv->planes[ch].base,
138					   type, driver_data);
139		if (ret)
140			return ret;
141		kirin_priv->planes[ch].ch = ch;
142		kirin_priv->planes[ch].hw_ctx = ctx;
143	}
144
145	/* crtc init */
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);
149	if (ret)
150		return ret;
151	kirin_priv->crtc.hw_ctx = ctx;
152	dev->dev_private = kirin_priv;
153
154	return 0;
155}
156
157static int kirin_drm_kms_init(struct drm_device *dev,
158			      const struct kirin_drm_data *driver_data)
159{
160	int ret;
161
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;
169
170	/* display controller init */
171	ret = kirin_drm_private_init(dev, driver_data);
172	if (ret)
173		goto err_mode_config_cleanup;
174
175	/* bind and init sub drivers */
176	ret = component_bind_all(dev->dev, dev);
177	if (ret) {
178		DRM_ERROR("failed to bind all component.\n");
179		goto err_private_cleanup;
180	}
181
182	/* vblank init */
183	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
184	if (ret) {
185		DRM_ERROR("failed to initialize vblank.\n");
186		goto err_unbind_all;
187	}
188
189	/* reset all the states of crtc/plane/encoder/connector */
190	drm_mode_config_reset(dev);
191
192	/* init kms poll for handling hpd */
193	drm_kms_helper_poll_init(dev);
194
195	return 0;
196
197err_unbind_all:
198	component_unbind_all(dev->dev, dev);
199err_private_cleanup:
200	kirin_drm_private_cleanup(dev);
201err_mode_config_cleanup:
202	drm_mode_config_cleanup(dev);
203	return ret;
204}
205
206static int kirin_drm_kms_cleanup(struct drm_device *dev)
207{
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);
212
213	return 0;
214}
215
216static int kirin_drm_bind(struct device *dev)
217{
218	struct kirin_drm_data *driver_data;
219	struct drm_device *drm_dev;
220	int ret;
221
222	driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev);
223	if (!driver_data)
224		return -EINVAL;
225
226	drm_dev = drm_dev_alloc(driver_data->driver, dev);
227	if (IS_ERR(drm_dev))
228		return PTR_ERR(drm_dev);
229	dev_set_drvdata(dev, drm_dev);
230
231	/* display controller init */
232	ret = kirin_drm_kms_init(drm_dev, driver_data);
233	if (ret)
234		goto err_drm_dev_put;
235
236	ret = drm_dev_register(drm_dev, 0);
237	if (ret)
238		goto err_kms_cleanup;
239
240	drm_fbdev_generic_setup(drm_dev, 32);
241
242	return 0;
243
244err_kms_cleanup:
245	kirin_drm_kms_cleanup(drm_dev);
246err_drm_dev_put:
247	drm_dev_put(drm_dev);
248	dev_set_drvdata(dev, NULL);
249
250	return ret;
251}
252
253static void kirin_drm_unbind(struct device *dev)
254{
255	struct drm_device *drm_dev = dev_get_drvdata(dev);
256
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);
261}
262
263static const struct component_master_ops kirin_drm_ops = {
264	.bind = kirin_drm_bind,
265	.unbind = kirin_drm_unbind,
266};
267
268static int kirin_drm_platform_probe(struct platform_device *pdev)
269{
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;
274
275	remote = of_graph_get_remote_node(np, 0, 0);
276	if (!remote)
277		return -ENODEV;
278
279	drm_of_component_match_add(dev, &match, component_compare_of, remote);
280	of_node_put(remote);
281
282	return component_master_add_with_match(dev, &kirin_drm_ops, match);
283}
284
285static void kirin_drm_platform_remove(struct platform_device *pdev)
286{
287	component_master_del(&pdev->dev, &kirin_drm_ops);
288}
289
290static void kirin_drm_platform_shutdown(struct platform_device *pdev)
291{
292	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
293}
294
295static const struct of_device_id kirin_drm_dt_ids[] = {
296	{ .compatible = "hisilicon,hi6220-ade",
297	  .data = &ade_driver_data,
298	},
299	{ /* end node */ },
300};
301MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
302
303static struct platform_driver kirin_drm_platform_driver = {
304	.probe = kirin_drm_platform_probe,
305	.remove_new = kirin_drm_platform_remove,
306	.shutdown = kirin_drm_platform_shutdown,
307	.driver = {
308		.name = "kirin-drm",
309		.of_match_table = kirin_drm_dt_ids,
310	},
311};
312
313drm_module_platform_driver(kirin_drm_platform_driver);
314
315MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
316MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
317MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
318MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
319MODULE_LICENSE("GPL v2");