File Index
Files and directories
Sign in
FILE

kirin_drm_drv.c

File preview with syntax highlighting.

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