162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 462306a36Sopenharmony_ci * Author:Mark Yao <mark.yao@rock-chips.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * based on exynos_drm_drv.c 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of_graph.h> 1462306a36Sopenharmony_ci#include <linux/of_platform.h> 1562306a36Sopenharmony_ci#include <linux/component.h> 1662306a36Sopenharmony_ci#include <linux/console.h> 1762306a36Sopenharmony_ci#include <linux/iommu.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <drm/drm_aperture.h> 2062306a36Sopenharmony_ci#include <drm/drm_drv.h> 2162306a36Sopenharmony_ci#include <drm/drm_fbdev_generic.h> 2262306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h> 2362306a36Sopenharmony_ci#include <drm/drm_of.h> 2462306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 2562306a36Sopenharmony_ci#include <drm/drm_vblank.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#if defined(CONFIG_ARM_DMA_USE_IOMMU) 2862306a36Sopenharmony_ci#include <asm/dma-iommu.h> 2962306a36Sopenharmony_ci#else 3062306a36Sopenharmony_ci#define arm_iommu_detach_device(...) ({ }) 3162306a36Sopenharmony_ci#define arm_iommu_release_mapping(...) ({ }) 3262306a36Sopenharmony_ci#define to_dma_iommu_mapping(dev) NULL 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "rockchip_drm_drv.h" 3662306a36Sopenharmony_ci#include "rockchip_drm_fb.h" 3762306a36Sopenharmony_ci#include "rockchip_drm_gem.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define DRIVER_NAME "rockchip" 4062306a36Sopenharmony_ci#define DRIVER_DESC "RockChip Soc DRM" 4162306a36Sopenharmony_ci#define DRIVER_DATE "20140818" 4262306a36Sopenharmony_ci#define DRIVER_MAJOR 1 4362306a36Sopenharmony_ci#define DRIVER_MINOR 0 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const struct drm_driver rockchip_drm_driver; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Attach a (component) device to the shared drm dma mapping from master drm 4962306a36Sopenharmony_ci * device. This is used by the VOPs to map GEM buffers to a common DMA 5062306a36Sopenharmony_ci * mapping. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ciint rockchip_drm_dma_attach_device(struct drm_device *drm_dev, 5362306a36Sopenharmony_ci struct device *dev) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct rockchip_drm_private *private = drm_dev->dev_private; 5662306a36Sopenharmony_ci int ret; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (!private->domain) 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) { 6262306a36Sopenharmony_ci struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (mapping) { 6562306a36Sopenharmony_ci arm_iommu_detach_device(dev); 6662306a36Sopenharmony_ci arm_iommu_release_mapping(mapping); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ret = iommu_attach_device(private->domain, dev); 7162306a36Sopenharmony_ci if (ret) { 7262306a36Sopenharmony_ci DRM_DEV_ERROR(dev, "Failed to attach iommu device\n"); 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid rockchip_drm_dma_detach_device(struct drm_device *drm_dev, 8062306a36Sopenharmony_ci struct device *dev) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct rockchip_drm_private *private = drm_dev->dev_private; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (!private->domain) 8562306a36Sopenharmony_ci return; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci iommu_detach_device(private->domain, dev); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid rockchip_drm_dma_init_device(struct drm_device *drm_dev, 9162306a36Sopenharmony_ci struct device *dev) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct rockchip_drm_private *private = drm_dev->dev_private; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (!device_iommu_mapped(dev)) 9662306a36Sopenharmony_ci private->iommu_dev = ERR_PTR(-ENODEV); 9762306a36Sopenharmony_ci else if (!private->iommu_dev) 9862306a36Sopenharmony_ci private->iommu_dev = dev; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int rockchip_drm_init_iommu(struct drm_device *drm_dev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct rockchip_drm_private *private = drm_dev->dev_private; 10462306a36Sopenharmony_ci struct iommu_domain_geometry *geometry; 10562306a36Sopenharmony_ci u64 start, end; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (IS_ERR_OR_NULL(private->iommu_dev)) 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci private->domain = iommu_domain_alloc(private->iommu_dev->bus); 11162306a36Sopenharmony_ci if (!private->domain) 11262306a36Sopenharmony_ci return -ENOMEM; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci geometry = &private->domain->geometry; 11562306a36Sopenharmony_ci start = geometry->aperture_start; 11662306a36Sopenharmony_ci end = geometry->aperture_end; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n", 11962306a36Sopenharmony_ci start, end); 12062306a36Sopenharmony_ci drm_mm_init(&private->mm, start, end - start + 1); 12162306a36Sopenharmony_ci mutex_init(&private->mm_lock); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void rockchip_iommu_cleanup(struct drm_device *drm_dev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct rockchip_drm_private *private = drm_dev->dev_private; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (!private->domain) 13162306a36Sopenharmony_ci return; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci drm_mm_takedown(&private->mm); 13462306a36Sopenharmony_ci iommu_domain_free(private->domain); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int rockchip_drm_bind(struct device *dev) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct drm_device *drm_dev; 14062306a36Sopenharmony_ci struct rockchip_drm_private *private; 14162306a36Sopenharmony_ci int ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Remove existing drivers that may own the framebuffer memory. */ 14462306a36Sopenharmony_ci ret = drm_aperture_remove_framebuffers(&rockchip_drm_driver); 14562306a36Sopenharmony_ci if (ret) { 14662306a36Sopenharmony_ci DRM_DEV_ERROR(dev, 14762306a36Sopenharmony_ci "Failed to remove existing framebuffers - %d.\n", 14862306a36Sopenharmony_ci ret); 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); 15362306a36Sopenharmony_ci if (IS_ERR(drm_dev)) 15462306a36Sopenharmony_ci return PTR_ERR(drm_dev); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci dev_set_drvdata(dev, drm_dev); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); 15962306a36Sopenharmony_ci if (!private) { 16062306a36Sopenharmony_ci ret = -ENOMEM; 16162306a36Sopenharmony_ci goto err_free; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci drm_dev->dev_private = private; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ret = drmm_mode_config_init(drm_dev); 16762306a36Sopenharmony_ci if (ret) 16862306a36Sopenharmony_ci goto err_free; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci rockchip_drm_mode_config_init(drm_dev); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Try to bind all sub drivers. */ 17362306a36Sopenharmony_ci ret = component_bind_all(dev, drm_dev); 17462306a36Sopenharmony_ci if (ret) 17562306a36Sopenharmony_ci goto err_free; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ret = rockchip_drm_init_iommu(drm_dev); 17862306a36Sopenharmony_ci if (ret) 17962306a36Sopenharmony_ci goto err_unbind_all; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); 18262306a36Sopenharmony_ci if (ret) 18362306a36Sopenharmony_ci goto err_iommu_cleanup; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci drm_mode_config_reset(drm_dev); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* init kms poll for handling hpd */ 18862306a36Sopenharmony_ci drm_kms_helper_poll_init(drm_dev); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ret = drm_dev_register(drm_dev, 0); 19162306a36Sopenharmony_ci if (ret) 19262306a36Sopenharmony_ci goto err_kms_helper_poll_fini; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci drm_fbdev_generic_setup(drm_dev, 0); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_cierr_kms_helper_poll_fini: 19862306a36Sopenharmony_ci drm_kms_helper_poll_fini(drm_dev); 19962306a36Sopenharmony_cierr_iommu_cleanup: 20062306a36Sopenharmony_ci rockchip_iommu_cleanup(drm_dev); 20162306a36Sopenharmony_cierr_unbind_all: 20262306a36Sopenharmony_ci component_unbind_all(dev, drm_dev); 20362306a36Sopenharmony_cierr_free: 20462306a36Sopenharmony_ci drm_dev_put(drm_dev); 20562306a36Sopenharmony_ci return ret; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void rockchip_drm_unbind(struct device *dev) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct drm_device *drm_dev = dev_get_drvdata(dev); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci drm_dev_unregister(drm_dev); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci drm_kms_helper_poll_fini(drm_dev); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci drm_atomic_helper_shutdown(drm_dev); 21762306a36Sopenharmony_ci component_unbind_all(dev, drm_dev); 21862306a36Sopenharmony_ci rockchip_iommu_cleanup(drm_dev); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci drm_dev_put(drm_dev); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciDEFINE_DRM_GEM_FOPS(rockchip_drm_driver_fops); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic const struct drm_driver rockchip_drm_driver = { 22662306a36Sopenharmony_ci .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 22762306a36Sopenharmony_ci .dumb_create = rockchip_gem_dumb_create, 22862306a36Sopenharmony_ci .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, 22962306a36Sopenharmony_ci .fops = &rockchip_drm_driver_fops, 23062306a36Sopenharmony_ci .name = DRIVER_NAME, 23162306a36Sopenharmony_ci .desc = DRIVER_DESC, 23262306a36Sopenharmony_ci .date = DRIVER_DATE, 23362306a36Sopenharmony_ci .major = DRIVER_MAJOR, 23462306a36Sopenharmony_ci .minor = DRIVER_MINOR, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23862306a36Sopenharmony_cistatic int rockchip_drm_sys_suspend(struct device *dev) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct drm_device *drm = dev_get_drvdata(dev); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci return drm_mode_config_helper_suspend(drm); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int rockchip_drm_sys_resume(struct device *dev) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct drm_device *drm = dev_get_drvdata(dev); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return drm_mode_config_helper_resume(drm); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci#endif 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic const struct dev_pm_ops rockchip_drm_pm_ops = { 25462306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend, 25562306a36Sopenharmony_ci rockchip_drm_sys_resume) 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define MAX_ROCKCHIP_SUB_DRIVERS 16 25962306a36Sopenharmony_cistatic struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; 26062306a36Sopenharmony_cistatic int num_rockchip_sub_drivers; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* 26362306a36Sopenharmony_ci * Get the endpoint id of the remote endpoint of the given encoder. This 26462306a36Sopenharmony_ci * information is used by the VOP2 driver to identify the encoder. 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * @rkencoder: The encoder to get the remote endpoint id from 26762306a36Sopenharmony_ci * @np: The encoder device node 26862306a36Sopenharmony_ci * @port: The number of the port leading to the VOP2 26962306a36Sopenharmony_ci * @reg: The endpoint number leading to the VOP2 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ciint rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rkencoder, 27262306a36Sopenharmony_ci struct device_node *np, int port, int reg) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct of_endpoint ep; 27562306a36Sopenharmony_ci struct device_node *en, *ren; 27662306a36Sopenharmony_ci int ret; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci en = of_graph_get_endpoint_by_regs(np, port, reg); 27962306a36Sopenharmony_ci if (!en) 28062306a36Sopenharmony_ci return -ENOENT; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ren = of_graph_get_remote_endpoint(en); 28362306a36Sopenharmony_ci if (!ren) 28462306a36Sopenharmony_ci return -ENOENT; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = of_graph_parse_endpoint(ren, &ep); 28762306a36Sopenharmony_ci if (ret) 28862306a36Sopenharmony_ci return ret; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci rkencoder->crtc_endpoint_id = ep.id; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* 29662306a36Sopenharmony_ci * Check if a vop endpoint is leading to a rockchip subdriver or bridge. 29762306a36Sopenharmony_ci * Should be called from the component bind stage of the drivers 29862306a36Sopenharmony_ci * to ensure that all subdrivers are probed. 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * @ep: endpoint of a rockchip vop 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * returns true if subdriver, false if external bridge and -ENODEV 30362306a36Sopenharmony_ci * if remote port does not contain a device. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ciint rockchip_drm_endpoint_is_subdriver(struct device_node *ep) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct device_node *node = of_graph_get_remote_port_parent(ep); 30862306a36Sopenharmony_ci struct platform_device *pdev; 30962306a36Sopenharmony_ci struct device_driver *drv; 31062306a36Sopenharmony_ci int i; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!node) 31362306a36Sopenharmony_ci return -ENODEV; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* status disabled will prevent creation of platform-devices */ 31662306a36Sopenharmony_ci if (!of_device_is_available(node)) { 31762306a36Sopenharmony_ci of_node_put(node); 31862306a36Sopenharmony_ci return -ENODEV; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci pdev = of_find_device_by_node(node); 32262306a36Sopenharmony_ci of_node_put(node); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* enabled non-platform-devices can immediately return here */ 32562306a36Sopenharmony_ci if (!pdev) 32662306a36Sopenharmony_ci return false; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* 32962306a36Sopenharmony_ci * All rockchip subdrivers have probed at this point, so 33062306a36Sopenharmony_ci * any device not having a driver now is an external bridge. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci drv = pdev->dev.driver; 33362306a36Sopenharmony_ci if (!drv) { 33462306a36Sopenharmony_ci platform_device_put(pdev); 33562306a36Sopenharmony_ci return false; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci for (i = 0; i < num_rockchip_sub_drivers; i++) { 33962306a36Sopenharmony_ci if (rockchip_sub_drivers[i] == to_platform_driver(drv)) { 34062306a36Sopenharmony_ci platform_device_put(pdev); 34162306a36Sopenharmony_ci return true; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci platform_device_put(pdev); 34662306a36Sopenharmony_ci return false; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void rockchip_drm_match_remove(struct device *dev) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct device_link *link; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) 35462306a36Sopenharmony_ci device_link_del(link); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic struct component_match *rockchip_drm_match_add(struct device *dev) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct component_match *match = NULL; 36062306a36Sopenharmony_ci int i; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (i = 0; i < num_rockchip_sub_drivers; i++) { 36362306a36Sopenharmony_ci struct platform_driver *drv = rockchip_sub_drivers[i]; 36462306a36Sopenharmony_ci struct device *p = NULL, *d; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci do { 36762306a36Sopenharmony_ci d = platform_find_device_by_driver(p, &drv->driver); 36862306a36Sopenharmony_ci put_device(p); 36962306a36Sopenharmony_ci p = d; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!d) 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci device_link_add(dev, d, DL_FLAG_STATELESS); 37562306a36Sopenharmony_ci component_match_add(dev, &match, component_compare_dev, d); 37662306a36Sopenharmony_ci } while (true); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (IS_ERR(match)) 38062306a36Sopenharmony_ci rockchip_drm_match_remove(dev); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return match ?: ERR_PTR(-ENODEV); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic const struct component_master_ops rockchip_drm_ops = { 38662306a36Sopenharmony_ci .bind = rockchip_drm_bind, 38762306a36Sopenharmony_ci .unbind = rockchip_drm_unbind, 38862306a36Sopenharmony_ci}; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int rockchip_drm_platform_of_probe(struct device *dev) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct device_node *np = dev->of_node; 39362306a36Sopenharmony_ci struct device_node *port; 39462306a36Sopenharmony_ci bool found = false; 39562306a36Sopenharmony_ci int i; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (!np) 39862306a36Sopenharmony_ci return -ENODEV; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci for (i = 0;; i++) { 40162306a36Sopenharmony_ci port = of_parse_phandle(np, "ports", i); 40262306a36Sopenharmony_ci if (!port) 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (!of_device_is_available(port->parent)) { 40662306a36Sopenharmony_ci of_node_put(port); 40762306a36Sopenharmony_ci continue; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci found = true; 41162306a36Sopenharmony_ci of_node_put(port); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (i == 0) { 41562306a36Sopenharmony_ci DRM_DEV_ERROR(dev, "missing 'ports' property\n"); 41662306a36Sopenharmony_ci return -ENODEV; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!found) { 42062306a36Sopenharmony_ci DRM_DEV_ERROR(dev, 42162306a36Sopenharmony_ci "No available vop found for display-subsystem.\n"); 42262306a36Sopenharmony_ci return -ENODEV; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int rockchip_drm_platform_probe(struct platform_device *pdev) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 43162306a36Sopenharmony_ci struct component_match *match = NULL; 43262306a36Sopenharmony_ci int ret; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ret = rockchip_drm_platform_of_probe(dev); 43562306a36Sopenharmony_ci if (ret) 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci match = rockchip_drm_match_add(dev); 43962306a36Sopenharmony_ci if (IS_ERR(match)) 44062306a36Sopenharmony_ci return PTR_ERR(match); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci ret = component_master_add_with_match(dev, &rockchip_drm_ops, match); 44362306a36Sopenharmony_ci if (ret < 0) { 44462306a36Sopenharmony_ci rockchip_drm_match_remove(dev); 44562306a36Sopenharmony_ci return ret; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void rockchip_drm_platform_remove(struct platform_device *pdev) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci component_master_del(&pdev->dev, &rockchip_drm_ops); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci rockchip_drm_match_remove(&pdev->dev); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void rockchip_drm_platform_shutdown(struct platform_device *pdev) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct drm_device *drm = platform_get_drvdata(pdev); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (drm) 46362306a36Sopenharmony_ci drm_atomic_helper_shutdown(drm); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic const struct of_device_id rockchip_drm_dt_ids[] = { 46762306a36Sopenharmony_ci { .compatible = "rockchip,display-subsystem", }, 46862306a36Sopenharmony_ci { /* sentinel */ }, 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic struct platform_driver rockchip_drm_platform_driver = { 47362306a36Sopenharmony_ci .probe = rockchip_drm_platform_probe, 47462306a36Sopenharmony_ci .remove_new = rockchip_drm_platform_remove, 47562306a36Sopenharmony_ci .shutdown = rockchip_drm_platform_shutdown, 47662306a36Sopenharmony_ci .driver = { 47762306a36Sopenharmony_ci .name = "rockchip-drm", 47862306a36Sopenharmony_ci .of_match_table = rockchip_drm_dt_ids, 47962306a36Sopenharmony_ci .pm = &rockchip_drm_pm_ops, 48062306a36Sopenharmony_ci }, 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci#define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \ 48462306a36Sopenharmony_ci if (IS_ENABLED(cond) && \ 48562306a36Sopenharmony_ci !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \ 48662306a36Sopenharmony_ci rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \ 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int __init rockchip_drm_init(void) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci int ret; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (drm_firmware_drivers_only()) 49462306a36Sopenharmony_ci return -ENODEV; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci num_rockchip_sub_drivers = 0; 49762306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); 49862306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2); 49962306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, 50062306a36Sopenharmony_ci CONFIG_ROCKCHIP_LVDS); 50162306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, 50262306a36Sopenharmony_ci CONFIG_ROCKCHIP_ANALOGIX_DP); 50362306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); 50462306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, 50562306a36Sopenharmony_ci CONFIG_ROCKCHIP_DW_HDMI); 50662306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver, 50762306a36Sopenharmony_ci CONFIG_ROCKCHIP_DW_MIPI_DSI); 50862306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); 50962306a36Sopenharmony_ci ADD_ROCKCHIP_SUB_DRIVER(rk3066_hdmi_driver, 51062306a36Sopenharmony_ci CONFIG_ROCKCHIP_RK3066_HDMI); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ret = platform_register_drivers(rockchip_sub_drivers, 51362306a36Sopenharmony_ci num_rockchip_sub_drivers); 51462306a36Sopenharmony_ci if (ret) 51562306a36Sopenharmony_ci return ret; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci ret = platform_driver_register(&rockchip_drm_platform_driver); 51862306a36Sopenharmony_ci if (ret) 51962306a36Sopenharmony_ci goto err_unreg_drivers; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cierr_unreg_drivers: 52462306a36Sopenharmony_ci platform_unregister_drivers(rockchip_sub_drivers, 52562306a36Sopenharmony_ci num_rockchip_sub_drivers); 52662306a36Sopenharmony_ci return ret; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic void __exit rockchip_drm_fini(void) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci platform_driver_unregister(&rockchip_drm_platform_driver); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci platform_unregister_drivers(rockchip_sub_drivers, 53462306a36Sopenharmony_ci num_rockchip_sub_drivers); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cimodule_init(rockchip_drm_init); 53862306a36Sopenharmony_cimodule_exit(rockchip_drm_fini); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciMODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>"); 54162306a36Sopenharmony_ciMODULE_DESCRIPTION("ROCKCHIP DRM Driver"); 54262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 543