// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2020 Unisoc Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sprd_drm.h" #define DRIVER_NAME "sprd" #define DRIVER_DESC "Spreadtrum SoCs' DRM Driver" #define DRIVER_DATE "20200201" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = { .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; static void sprd_drm_mode_config_init(struct drm_device *drm) { drm->mode_config.min_width = 0; drm->mode_config.min_height = 0; drm->mode_config.max_width = 8192; drm->mode_config.max_height = 8192; drm->mode_config.funcs = &sprd_drm_mode_config_funcs; drm->mode_config.helper_private = &sprd_drm_mode_config_helper; } DEFINE_DRM_GEM_CMA_FOPS(sprd_drm_fops); static struct drm_driver sprd_drm_drv = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &sprd_drm_fops, /* GEM Operations */ DRM_GEM_CMA_DRIVER_OPS, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, }; static int sprd_drm_bind(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm; struct sprd_drm *sprd; int ret; sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm); if (IS_ERR(sprd)) return PTR_ERR(sprd); drm = &sprd->drm; platform_set_drvdata(pdev, drm); ret = drmm_mode_config_init(drm); if (ret) return ret; sprd_drm_mode_config_init(drm); /* bind and init sub drivers */ ret = component_bind_all(drm->dev, drm); if (ret) { drm_err(drm, "failed to bind all component.\n"); return ret; } /* vblank init */ ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret) { drm_err(drm, "failed to initialize vblank.\n"); goto err_unbind_all; } /* reset all the states of crtc/plane/encoder/connector */ drm_mode_config_reset(drm); /* init kms poll for handling hpd */ drm_kms_helper_poll_init(drm); ret = drm_dev_register(drm, 0); if (ret < 0) goto err_kms_helper_poll_fini; return 0; err_kms_helper_poll_fini: drm_kms_helper_poll_fini(drm); err_unbind_all: component_unbind_all(drm->dev, drm); return ret; } static void sprd_drm_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); component_unbind_all(drm->dev, drm); } static const struct component_master_ops drm_component_ops = { .bind = sprd_drm_bind, .unbind = sprd_drm_unbind, }; static int sprd_drm_probe(struct platform_device *pdev) { return drm_of_component_probe(&pdev->dev, component_compare_of, &drm_component_ops); } static int sprd_drm_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &drm_component_ops); return 0; } static void sprd_drm_shutdown(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); if (!drm) { dev_warn(&pdev->dev, "drm device is not available, no shutdown\n"); return; } drm_atomic_helper_shutdown(drm); } static const struct of_device_id drm_match_table[] = { { .compatible = "sprd,display-subsystem", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, drm_match_table); static struct platform_driver sprd_drm_driver = { .probe = sprd_drm_probe, .remove = sprd_drm_remove, .shutdown = sprd_drm_shutdown, .driver = { .name = "sprd-drm-drv", .of_match_table = drm_match_table, }, }; static struct platform_driver *sprd_drm_drivers[] = { &sprd_drm_driver, &sprd_dpu_driver, &sprd_dsi_driver, }; static int __init sprd_drm_init(void) { if (drm_firmware_drivers_only()) return -ENODEV; return platform_register_drivers(sprd_drm_drivers, ARRAY_SIZE(sprd_drm_drivers)); } static void __exit sprd_drm_exit(void) { platform_unregister_drivers(sprd_drm_drivers, ARRAY_SIZE(sprd_drm_drivers)); } module_init(sprd_drm_init); module_exit(sprd_drm_exit); MODULE_AUTHOR("Leon He "); MODULE_AUTHOR("Kevin Tang "); MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver"); MODULE_LICENSE("GPL v2");