From 34d28b23b61b0ec40e739c5f0cfed4531a7ccee0 Mon Sep 17 00:00:00 2001 From: Nabige Aala Date: Wed, 1 Apr 2026 16:30:51 +0530 Subject: [PATCH] QCLINUX: drm/msm: Auto-detect separate GPU KMS mode based on HW topology On platforms with multiple display subsystems, such as SA8775P, the GPU binds to the first display subsystem that probes. This implicit binding prevents subsequent display subsystems from probing successfully, breaking multi-display support. Use the tristate separate_gpu_kms module parameter with the default value set to auto (-1). In auto mode, the driver selects the binding behavior based on the number of GPUs and display subsystems. This allows display subsystems to probe independently when required, while preserving the existing single-card behavior on simpler systems. The separate_gpu_kms module parameter has the following semantics: -1 (auto, default): Select the binding mode based on hardware topology. If exactly one GPU and one display subsystem are present, bind them together to form a single DRM device. Otherwise, expose the GPU and display subsystems as separate DRM devices. 0: Always bind the GPU and display together to form a single DRM device. 1: Always expose the GPU and display subsystems as separate DRM devices. This ensures correct probing on multi-display platforms without affecting single-display, single-GPU systems. Signed-off-by: Mahadevan P Signed-off-by: Nabige Aala --- drivers/gpu/drm/msm/adreno/adreno_device.c | 2 +- drivers/gpu/drm/msm/msm_drv.c | 46 ++++++++++++++++++---- drivers/gpu/drm/msm/msm_drv.h | 4 +- drivers/gpu/drm/msm/msm_mdss.c | 15 +++++++ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 28f744f3caf7c..5363e809ea581 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -270,7 +270,7 @@ static const struct component_ops a3xx_ops = { static int adreno_probe(struct platform_device *pdev) { if (of_device_is_compatible(pdev->dev.of_node, "amd,imageon") || - msm_gpu_no_components()) + msm_seperate_gpu_kms_components()) return msm_gpu_probe(pdev, &a3xx_ops); return component_add(&pdev->dev, &a3xx_ops); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 7e977fec41007..dafd0f7482d9d 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -54,16 +54,48 @@ static bool modeset = true; MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (1=on (default), 0=disable)"); module_param(modeset, bool, 0600); -static bool separate_gpu_kms; -MODULE_PARM_DESC(separate_gpu_drm, "Use separate DRM device for the GPU (0=single DRM device for both GPU and display (default), 1=two DRM devices)"); -module_param(separate_gpu_kms, bool, 0400); +static int separate_gpu_kms = -1; +MODULE_PARM_DESC(separate_gpu_kms, + "Use separate DRM device for the GPU " + "(-1=auto (default), 0=single DRM device, 1=separate DRM devices)"); +module_param(separate_gpu_kms, int, 0400); DECLARE_FAULT_ATTR(fail_gem_alloc); DECLARE_FAULT_ATTR(fail_gem_iova); -bool msm_gpu_no_components(void) +static const struct of_device_id msm_gpu_match[]; + +static int msm_count_gpus(void) +{ + struct device_node *np; + int count = 0; + + for_each_matching_node(np, msm_gpu_match) { + if (of_device_is_available(np) && adreno_has_gpu(np)) + count++; + } + + return count; +} + +static bool msm_separate_gpu_kms_auto(void) +{ + int gpus = msm_count_gpus(); + int mdss = msm_mdss_count_masters(); + + if (mdss == 2 && gpus == 1) + return true; + + return false; +} + +bool msm_seperate_gpu_kms_components(void) { - return separate_gpu_kms; + if (separate_gpu_kms == 1) + return true; + if (separate_gpu_kms == 0) + return false; + return msm_separate_gpu_kms_auto(); } static int msm_drm_uninit(struct device *dev, const struct component_ops *gpu_ops) @@ -1018,7 +1050,7 @@ static int add_gpu_components(struct device *dev, static int msm_drm_bind(struct device *dev) { return msm_drm_init(dev, - msm_gpu_no_components() ? + msm_seperate_gpu_kms_components() ? &msm_kms_driver : &msm_driver, NULL); @@ -1057,7 +1089,7 @@ int msm_drv_probe(struct device *master_dev, return ret; } - if (!msm_gpu_no_components()) { + if (!msm_seperate_gpu_kms_components()) { ret = add_gpu_components(master_dev, &match); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 6d847d593f1ae..44be401444569 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -555,6 +555,8 @@ void msm_kms_shutdown(struct platform_device *pdev); bool msm_disp_drv_should_bind(struct device *dev, bool dpu_driver); -bool msm_gpu_no_components(void); +bool msm_seperate_gpu_kms_components(void); + +int msm_mdss_count_masters(void); #endif /* __MSM_DRV_H__ */ diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 944a4e08a68e1..9eb6a69d7d1e0 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -73,6 +73,21 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, return 0; } +static const struct of_device_id mdss_dt_match[]; + +int msm_mdss_count_masters(void) +{ + struct device_node *np; + int count = 0; + + for_each_matching_node(np, mdss_dt_match) { + if (of_device_is_available(np)) + count++; + } + + return count; +} + static void msm_mdss_irq(struct irq_desc *desc) { struct msm_mdss *msm_mdss = irq_desc_get_handler_data(desc);