brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 1266698 Raw
320 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Hisilicon Kirin SoCs drm master driver4 *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_dma.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	233 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 that48	 * drm_of_find_possible_crtcs call works49	 */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 init129	 * TODO: Now only support primary plane, overlay planes130	 * 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		else136			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_dma_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");320