xref: /openbmc/linux/drivers/gpu/drm/sprd/sprd_drm.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
143531eddSKevin Tang // SPDX-License-Identifier: GPL-2.0
243531eddSKevin Tang /*
343531eddSKevin Tang  * Copyright (C) 2020 Unisoc Inc.
443531eddSKevin Tang  */
543531eddSKevin Tang 
643531eddSKevin Tang #include <linux/component.h>
743531eddSKevin Tang #include <linux/dma-mapping.h>
8*722d4f06SRob Herring #include <linux/mod_devicetable.h>
943531eddSKevin Tang #include <linux/module.h>
1043531eddSKevin Tang #include <linux/mutex.h>
1143531eddSKevin Tang #include <linux/of_graph.h>
12*722d4f06SRob Herring #include <linux/platform_device.h>
1343531eddSKevin Tang 
1443531eddSKevin Tang #include <drm/drm_atomic_helper.h>
1543531eddSKevin Tang #include <drm/drm_drv.h>
164a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
1743531eddSKevin Tang #include <drm/drm_gem_framebuffer_helper.h>
1843531eddSKevin Tang #include <drm/drm_of.h>
1943531eddSKevin Tang #include <drm/drm_probe_helper.h>
2043531eddSKevin Tang #include <drm/drm_vblank.h>
2143531eddSKevin Tang 
2243531eddSKevin Tang #include "sprd_drm.h"
2343531eddSKevin Tang 
2443531eddSKevin Tang #define DRIVER_NAME	"sprd"
2543531eddSKevin Tang #define DRIVER_DESC	"Spreadtrum SoCs' DRM Driver"
2643531eddSKevin Tang #define DRIVER_DATE	"20200201"
2743531eddSKevin Tang #define DRIVER_MAJOR	1
2843531eddSKevin Tang #define DRIVER_MINOR	0
2943531eddSKevin Tang 
3043531eddSKevin Tang static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = {
3143531eddSKevin Tang 	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
3243531eddSKevin Tang };
3343531eddSKevin Tang 
3443531eddSKevin Tang static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = {
3543531eddSKevin Tang 	.fb_create = drm_gem_fb_create,
3643531eddSKevin Tang 	.atomic_check = drm_atomic_helper_check,
3743531eddSKevin Tang 	.atomic_commit = drm_atomic_helper_commit,
3843531eddSKevin Tang };
3943531eddSKevin Tang 
sprd_drm_mode_config_init(struct drm_device * drm)4043531eddSKevin Tang static void sprd_drm_mode_config_init(struct drm_device *drm)
4143531eddSKevin Tang {
4243531eddSKevin Tang 	drm->mode_config.min_width = 0;
4343531eddSKevin Tang 	drm->mode_config.min_height = 0;
4443531eddSKevin Tang 	drm->mode_config.max_width = 8192;
4543531eddSKevin Tang 	drm->mode_config.max_height = 8192;
4643531eddSKevin Tang 
4743531eddSKevin Tang 	drm->mode_config.funcs = &sprd_drm_mode_config_funcs;
4843531eddSKevin Tang 	drm->mode_config.helper_private = &sprd_drm_mode_config_helper;
4943531eddSKevin Tang }
5043531eddSKevin Tang 
514a83c26aSDanilo Krummrich DEFINE_DRM_GEM_DMA_FOPS(sprd_drm_fops);
5243531eddSKevin Tang 
5343531eddSKevin Tang static struct drm_driver sprd_drm_drv = {
5443531eddSKevin Tang 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
5543531eddSKevin Tang 	.fops			= &sprd_drm_fops,
5643531eddSKevin Tang 
5743531eddSKevin Tang 	/* GEM Operations */
584a83c26aSDanilo Krummrich 	DRM_GEM_DMA_DRIVER_OPS,
5943531eddSKevin Tang 
6043531eddSKevin Tang 	.name			= DRIVER_NAME,
6143531eddSKevin Tang 	.desc			= DRIVER_DESC,
6243531eddSKevin Tang 	.date			= DRIVER_DATE,
6343531eddSKevin Tang 	.major			= DRIVER_MAJOR,
6443531eddSKevin Tang 	.minor			= DRIVER_MINOR,
6543531eddSKevin Tang };
6643531eddSKevin Tang 
sprd_drm_bind(struct device * dev)6743531eddSKevin Tang static int sprd_drm_bind(struct device *dev)
6843531eddSKevin Tang {
6943531eddSKevin Tang 	struct platform_device *pdev = to_platform_device(dev);
7043531eddSKevin Tang 	struct drm_device *drm;
7143531eddSKevin Tang 	struct sprd_drm *sprd;
7243531eddSKevin Tang 	int ret;
7343531eddSKevin Tang 
7443531eddSKevin Tang 	sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm);
7543531eddSKevin Tang 	if (IS_ERR(sprd))
7643531eddSKevin Tang 		return PTR_ERR(sprd);
7743531eddSKevin Tang 
7843531eddSKevin Tang 	drm = &sprd->drm;
7943531eddSKevin Tang 	platform_set_drvdata(pdev, drm);
8043531eddSKevin Tang 
8143531eddSKevin Tang 	ret = drmm_mode_config_init(drm);
8243531eddSKevin Tang 	if (ret)
8343531eddSKevin Tang 		return ret;
8443531eddSKevin Tang 
8543531eddSKevin Tang 	sprd_drm_mode_config_init(drm);
8643531eddSKevin Tang 
8743531eddSKevin Tang 	/* bind and init sub drivers */
8843531eddSKevin Tang 	ret = component_bind_all(drm->dev, drm);
8943531eddSKevin Tang 	if (ret) {
9043531eddSKevin Tang 		drm_err(drm, "failed to bind all component.\n");
9143531eddSKevin Tang 		return ret;
9243531eddSKevin Tang 	}
9343531eddSKevin Tang 
9443531eddSKevin Tang 	/* vblank init */
9543531eddSKevin Tang 	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
9643531eddSKevin Tang 	if (ret) {
9743531eddSKevin Tang 		drm_err(drm, "failed to initialize vblank.\n");
9843531eddSKevin Tang 		goto err_unbind_all;
9943531eddSKevin Tang 	}
10043531eddSKevin Tang 
10143531eddSKevin Tang 	/* reset all the states of crtc/plane/encoder/connector */
10243531eddSKevin Tang 	drm_mode_config_reset(drm);
10343531eddSKevin Tang 
10443531eddSKevin Tang 	/* init kms poll for handling hpd */
10543531eddSKevin Tang 	drm_kms_helper_poll_init(drm);
10643531eddSKevin Tang 
10743531eddSKevin Tang 	ret = drm_dev_register(drm, 0);
10843531eddSKevin Tang 	if (ret < 0)
10943531eddSKevin Tang 		goto err_kms_helper_poll_fini;
11043531eddSKevin Tang 
11143531eddSKevin Tang 	return 0;
11243531eddSKevin Tang 
11343531eddSKevin Tang err_kms_helper_poll_fini:
11443531eddSKevin Tang 	drm_kms_helper_poll_fini(drm);
11543531eddSKevin Tang err_unbind_all:
11643531eddSKevin Tang 	component_unbind_all(drm->dev, drm);
11743531eddSKevin Tang 	return ret;
11843531eddSKevin Tang }
11943531eddSKevin Tang 
sprd_drm_unbind(struct device * dev)12043531eddSKevin Tang static void sprd_drm_unbind(struct device *dev)
12143531eddSKevin Tang {
12243531eddSKevin Tang 	struct drm_device *drm = dev_get_drvdata(dev);
12343531eddSKevin Tang 
12443531eddSKevin Tang 	drm_dev_unregister(drm);
12543531eddSKevin Tang 
12643531eddSKevin Tang 	drm_kms_helper_poll_fini(drm);
12743531eddSKevin Tang 
12843531eddSKevin Tang 	component_unbind_all(drm->dev, drm);
12943531eddSKevin Tang }
13043531eddSKevin Tang 
13143531eddSKevin Tang static const struct component_master_ops drm_component_ops = {
13243531eddSKevin Tang 	.bind = sprd_drm_bind,
13343531eddSKevin Tang 	.unbind = sprd_drm_unbind,
13443531eddSKevin Tang };
13543531eddSKevin Tang 
sprd_drm_probe(struct platform_device * pdev)13643531eddSKevin Tang static int sprd_drm_probe(struct platform_device *pdev)
13743531eddSKevin Tang {
13811ef5c77SYong Wu 	return drm_of_component_probe(&pdev->dev, component_compare_of, &drm_component_ops);
13943531eddSKevin Tang }
14043531eddSKevin Tang 
sprd_drm_remove(struct platform_device * pdev)14143531eddSKevin Tang static int sprd_drm_remove(struct platform_device *pdev)
14243531eddSKevin Tang {
14343531eddSKevin Tang 	component_master_del(&pdev->dev, &drm_component_ops);
14443531eddSKevin Tang 	return 0;
14543531eddSKevin Tang }
14643531eddSKevin Tang 
sprd_drm_shutdown(struct platform_device * pdev)14743531eddSKevin Tang static void sprd_drm_shutdown(struct platform_device *pdev)
14843531eddSKevin Tang {
14943531eddSKevin Tang 	struct drm_device *drm = platform_get_drvdata(pdev);
15043531eddSKevin Tang 
15143531eddSKevin Tang 	if (!drm) {
1528668658aSKevin Tang 		dev_warn(&pdev->dev, "drm device is not available, no shutdown\n");
15343531eddSKevin Tang 		return;
15443531eddSKevin Tang 	}
15543531eddSKevin Tang 
15643531eddSKevin Tang 	drm_atomic_helper_shutdown(drm);
15743531eddSKevin Tang }
15843531eddSKevin Tang 
15943531eddSKevin Tang static const struct of_device_id drm_match_table[] = {
16043531eddSKevin Tang 	{ .compatible = "sprd,display-subsystem", },
16143531eddSKevin Tang 	{ /* sentinel */ },
16243531eddSKevin Tang };
16343531eddSKevin Tang MODULE_DEVICE_TABLE(of, drm_match_table);
16443531eddSKevin Tang 
16543531eddSKevin Tang static struct platform_driver sprd_drm_driver = {
16643531eddSKevin Tang 	.probe = sprd_drm_probe,
16743531eddSKevin Tang 	.remove = sprd_drm_remove,
16843531eddSKevin Tang 	.shutdown = sprd_drm_shutdown,
16943531eddSKevin Tang 	.driver = {
17043531eddSKevin Tang 		.name = "sprd-drm-drv",
17143531eddSKevin Tang 		.of_match_table = drm_match_table,
17243531eddSKevin Tang 	},
17343531eddSKevin Tang };
17443531eddSKevin Tang 
17543531eddSKevin Tang static struct platform_driver *sprd_drm_drivers[]  = {
17643531eddSKevin Tang 	&sprd_drm_driver,
177b07bcf34SKevin Tang 	&sprd_dpu_driver,
1781c66496bSKevin Tang 	&sprd_dsi_driver,
17943531eddSKevin Tang };
18043531eddSKevin Tang 
sprd_drm_init(void)18143531eddSKevin Tang static int __init sprd_drm_init(void)
18243531eddSKevin Tang {
1835e66e818SJavier Martinez Canillas 	if (drm_firmware_drivers_only())
1845e66e818SJavier Martinez Canillas 		return -ENODEV;
1855e66e818SJavier Martinez Canillas 
18643531eddSKevin Tang 	return platform_register_drivers(sprd_drm_drivers,
18743531eddSKevin Tang 					ARRAY_SIZE(sprd_drm_drivers));
18843531eddSKevin Tang }
18943531eddSKevin Tang 
sprd_drm_exit(void)19043531eddSKevin Tang static void __exit sprd_drm_exit(void)
19143531eddSKevin Tang {
19243531eddSKevin Tang 	platform_unregister_drivers(sprd_drm_drivers,
19343531eddSKevin Tang 				    ARRAY_SIZE(sprd_drm_drivers));
19443531eddSKevin Tang }
19543531eddSKevin Tang 
19643531eddSKevin Tang module_init(sprd_drm_init);
19743531eddSKevin Tang module_exit(sprd_drm_exit);
19843531eddSKevin Tang 
19943531eddSKevin Tang MODULE_AUTHOR("Leon He <leon.he@unisoc.com>");
20043531eddSKevin Tang MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>");
20143531eddSKevin Tang MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver");
20243531eddSKevin Tang MODULE_LICENSE("GPL v2");
203