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