Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2020 Unisoc Inc.
  4 */
  5
  6#include <linux/component.h>
  7#include <linux/dma-mapping.h>
  8#include <linux/module.h>
  9#include <linux/mutex.h>
 10#include <linux/of_graph.h>
 11#include <linux/of_platform.h>
 12
 13#include <drm/drm_atomic_helper.h>
 14#include <drm/drm_crtc_helper.h>
 15#include <drm/drm_drv.h>
 16#include <drm/drm_gem_dma_helper.h>
 17#include <drm/drm_gem_framebuffer_helper.h>
 18#include <drm/drm_of.h>
 19#include <drm/drm_probe_helper.h>
 20#include <drm/drm_vblank.h>
 21
 22#include "sprd_drm.h"
 23
 24#define DRIVER_NAME	"sprd"
 25#define DRIVER_DESC	"Spreadtrum SoCs' DRM Driver"
 26#define DRIVER_DATE	"20200201"
 27#define DRIVER_MAJOR	1
 28#define DRIVER_MINOR	0
 29
 30static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = {
 31	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 32};
 33
 34static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = {
 35	.fb_create = drm_gem_fb_create,
 36	.atomic_check = drm_atomic_helper_check,
 37	.atomic_commit = drm_atomic_helper_commit,
 38};
 39
 40static void sprd_drm_mode_config_init(struct drm_device *drm)
 41{
 42	drm->mode_config.min_width = 0;
 43	drm->mode_config.min_height = 0;
 44	drm->mode_config.max_width = 8192;
 45	drm->mode_config.max_height = 8192;
 46
 47	drm->mode_config.funcs = &sprd_drm_mode_config_funcs;
 48	drm->mode_config.helper_private = &sprd_drm_mode_config_helper;
 49}
 50
 51DEFINE_DRM_GEM_DMA_FOPS(sprd_drm_fops);
 52
 53static struct drm_driver sprd_drm_drv = {
 54	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 55	.fops			= &sprd_drm_fops,
 56
 57	/* GEM Operations */
 58	DRM_GEM_DMA_DRIVER_OPS,
 59
 60	.name			= DRIVER_NAME,
 61	.desc			= DRIVER_DESC,
 62	.date			= DRIVER_DATE,
 63	.major			= DRIVER_MAJOR,
 64	.minor			= DRIVER_MINOR,
 65};
 66
 67static int sprd_drm_bind(struct device *dev)
 68{
 69	struct platform_device *pdev = to_platform_device(dev);
 70	struct drm_device *drm;
 71	struct sprd_drm *sprd;
 72	int ret;
 73
 74	sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm);
 75	if (IS_ERR(sprd))
 76		return PTR_ERR(sprd);
 77
 78	drm = &sprd->drm;
 79	platform_set_drvdata(pdev, drm);
 80
 81	ret = drmm_mode_config_init(drm);
 82	if (ret)
 83		return ret;
 84
 85	sprd_drm_mode_config_init(drm);
 86
 87	/* bind and init sub drivers */
 88	ret = component_bind_all(drm->dev, drm);
 89	if (ret) {
 90		drm_err(drm, "failed to bind all component.\n");
 91		return ret;
 92	}
 93
 94	/* vblank init */
 95	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
 96	if (ret) {
 97		drm_err(drm, "failed to initialize vblank.\n");
 98		goto err_unbind_all;
 99	}
100
101	/* reset all the states of crtc/plane/encoder/connector */
102	drm_mode_config_reset(drm);
103
104	/* init kms poll for handling hpd */
105	drm_kms_helper_poll_init(drm);
106
107	ret = drm_dev_register(drm, 0);
108	if (ret < 0)
109		goto err_kms_helper_poll_fini;
110
111	return 0;
112
113err_kms_helper_poll_fini:
114	drm_kms_helper_poll_fini(drm);
115err_unbind_all:
116	component_unbind_all(drm->dev, drm);
117	return ret;
118}
119
120static void sprd_drm_unbind(struct device *dev)
121{
122	struct drm_device *drm = dev_get_drvdata(dev);
123
124	drm_dev_unregister(drm);
125
126	drm_kms_helper_poll_fini(drm);
127
128	component_unbind_all(drm->dev, drm);
129}
130
131static const struct component_master_ops drm_component_ops = {
132	.bind = sprd_drm_bind,
133	.unbind = sprd_drm_unbind,
134};
135
136static int sprd_drm_probe(struct platform_device *pdev)
137{
138	return drm_of_component_probe(&pdev->dev, component_compare_of, &drm_component_ops);
139}
140
141static int sprd_drm_remove(struct platform_device *pdev)
142{
143	component_master_del(&pdev->dev, &drm_component_ops);
144	return 0;
145}
146
147static void sprd_drm_shutdown(struct platform_device *pdev)
148{
149	struct drm_device *drm = platform_get_drvdata(pdev);
150
151	if (!drm) {
152		dev_warn(&pdev->dev, "drm device is not available, no shutdown\n");
153		return;
154	}
155
156	drm_atomic_helper_shutdown(drm);
157}
158
159static const struct of_device_id drm_match_table[] = {
160	{ .compatible = "sprd,display-subsystem", },
161	{ /* sentinel */ },
162};
163MODULE_DEVICE_TABLE(of, drm_match_table);
164
165static struct platform_driver sprd_drm_driver = {
166	.probe = sprd_drm_probe,
167	.remove = sprd_drm_remove,
168	.shutdown = sprd_drm_shutdown,
169	.driver = {
170		.name = "sprd-drm-drv",
171		.of_match_table = drm_match_table,
172	},
173};
174
175static struct platform_driver *sprd_drm_drivers[]  = {
176	&sprd_drm_driver,
177	&sprd_dpu_driver,
178	&sprd_dsi_driver,
179};
180
181static int __init sprd_drm_init(void)
182{
183	if (drm_firmware_drivers_only())
184		return -ENODEV;
185
186	return platform_register_drivers(sprd_drm_drivers,
187					ARRAY_SIZE(sprd_drm_drivers));
188}
189
190static void __exit sprd_drm_exit(void)
191{
192	platform_unregister_drivers(sprd_drm_drivers,
193				    ARRAY_SIZE(sprd_drm_drivers));
194}
195
196module_init(sprd_drm_init);
197module_exit(sprd_drm_exit);
198
199MODULE_AUTHOR("Leon He <leon.he@unisoc.com>");
200MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>");
201MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver");
202MODULE_LICENSE("GPL v2");