On Mon, Oct 26, 2026 at 11:51:30AM +0530, Jayant Shekhar wrote:
> Add the DCP function driver that binds the VirtIO device to MSM
> DRM. Without a function driver, Linux cannot establish HFI queues,
> discover firmware capabilities, or register the firmware-owned
> display backend.
> 
> Set up the DCP DMA and IOMMU identity, initialize VirtIO and HFI
> transport, register the MSM DRM component, and synchronize suspend,
> resume, remove, and shutdown with in-flight HFI activity.
> 
> Assisted-by: LLM
> Signed-off-by: Jayant Shekhar <[email protected]>
> ---
>  drivers/gpu/drm/msm/Makefile         |   2 +
>  drivers/gpu/drm/msm/dcp/dcp_drv.c    | 191 ++++++++++++++++++++++++++
>  drivers/gpu/drm/msm/dcp/dcp_drv.h    |  17 +++
>  drivers/gpu/drm/msm/dcp/dcp_virtio.c | 258 
> +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/msm/dcp/dcp_virtio.h |   2 +
>  drivers/gpu/drm/msm/msm_drv.c        |   6 +-
>  drivers/gpu/drm/msm/msm_drv.h        |   2 +
>  7 files changed, 475 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index e1a995a8c980..ffdb159dd9ad 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -85,6 +85,8 @@ msm-display-$(CONFIG_DRM_MSM_DCP) += \
>       dcp/dcp_hfi_plane.o \
>       dcp/dcp_ipcc.o \
>       dcp/dcp_encoder.o \
> +     dcp/dcp_drv.o \
> +     dcp/dcp_virtio.o \
>       dcp/dcp_virtio_transport.o \
>       dcp/hfi/hfi_packer.o \
>       dcp/hfi/hfi_unpacker.o \
> diff --git a/drivers/gpu/drm/msm/dcp/dcp_drv.c 
> b/drivers/gpu/drm/msm/dcp/dcp_drv.c
> new file mode 100644
> index 000000000000..8c38de883bf6
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/dcp/dcp_drv.c
> @@ -0,0 +1,191 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * DCP VirtIO driver.
> + */
> +
> +#include <linux/component.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/panic_notifier.h>
> +#include <linux/pm_runtime.h>
> +
> +#define DCP_DPU_AUTOSUSPEND_DELAY_MS 5000
> +
> +#include "dcp_drv.h"
> +#include "dcp_dpu_kms.h"
> +#include "dcp_hfi.h"
> +#include "dcp_ipcc.h"
> +#include "dcp_virtio.h"
> +#include "msm_drv.h"
> +#include "msm_kms.h"
> +
> +int dcp_subsystem_dev_init(struct dcp_drv *drv)
> +{
> +     struct virtio_device *vdev = drv->vdev;
> +     struct device_node *dcp_subsystem_node;
> +     struct platform_device *pdev;
> +     struct device *dev;
> +     char busid[32];
> +     bool iommu_mapped;
> +     int ret;
> +
> +     dcp_subsystem_node = of_node_get(vdev->dev.of_node);
> +     if (!dcp_subsystem_node) {
> +             dev_err(&vdev->dev, "no DCP subsystem DT node\n");
> +             return -ENODEV;
> +     }
> +
> +     snprintf(busid, sizeof(busid), "dcp-subsystem.%s", 
> dev_name(vdev->dev.parent));
> +
> +     /*
> +      * DCP is discovered through VirtIO, but display/HFI buffers must be
> +      * mapped through the dcp-subsystem node's DMA/IOMMU identity. Create a
> +      * platform device for that DT node so DMA API and msm_kms_init_vm() use

Does DMA API require platform_device or would it work with the generic
struct device? In the latter case, should the MSM layer be changed to
pass struct device instead of struct platform_device?

> +      * the display function's IOMMU domain.
> +      */
> +     pdev = of_platform_device_create(dcp_subsystem_node, busid, 
> vdev->dev.parent);
> +     if (!pdev) {
> +             dev_err(&vdev->dev, "dcp_subsystem_dev creation failed\n");
> +             of_node_put(dcp_subsystem_node);
> +             return -ENODEV;
> +     }
> +     dev = &pdev->dev;
> +
> +     dev->dma_parms = &drv->dcp_subsystem_dma_parms;
> +     dma_set_max_seg_size(dev, UINT_MAX);
> +
> +     ret = of_dma_configure_id(dev, dcp_subsystem_node, true, NULL);
> +     if (ret) {
> +             dev_err(dev, "of_dma_configure_id failed: %d\n", ret);
> +             goto err_destroy;
> +     }
> +
> +     iommu_mapped = device_iommu_mapped(dev);
> +     if (!iommu_mapped) {
> +             dev_err(dev, "no IOMMU group attached\n");
> +             ret = -ENODEV;
> +             goto err_destroy;
> +     }
> +
> +     dev_dbg(dev, "dcp-subsystem: iommu_mapped=%d iommu_group=%d\n",
> +             iommu_mapped,
> +             dev->iommu_group ? iommu_group_id(dev->iommu_group) : -1);
> +
> +     pm_runtime_set_active(dev);
> +     pm_runtime_enable(dev);
> +     pm_runtime_set_autosuspend_delay(dev, DCP_DPU_AUTOSUSPEND_DELAY_MS);
> +     pm_runtime_use_autosuspend(dev);
> +
> +     drv->dcp_subsystem_dev = pdev;
> +     drv->dcp_subsystem_node = dcp_subsystem_node;
> +
> +     return 0;
> +
> +err_destroy:
> +     of_platform_device_destroy(dev, NULL);
> +     of_node_put(dcp_subsystem_node);
> +     return ret;
> +}
> +
> +void dcp_subsystem_dev_deinit(struct dcp_drv *drv)
> +{
> +     if (!drv->dcp_subsystem_dev)
> +             return;
> +
> +     pm_runtime_disable(&drv->dcp_subsystem_dev->dev);
> +     of_platform_device_destroy(&drv->dcp_subsystem_dev->dev, NULL);
> +     of_node_put(drv->dcp_subsystem_node);
> +     drv->dcp_subsystem_dev = NULL;
> +}
> +
> +int dcp_pm_prepare(struct device *vdev_dev)
> +{
> +     struct dcp_drv *drv = vdev_dev ?
> +             dev_to_virtio(vdev_dev)->priv : NULL;
> +
> +     if (!drv || !drv->dcp_subsystem_dev)
> +             return 0;
> +
> +     return msm_kms_pm_prepare(&drv->dcp_subsystem_dev->dev);
> +}
> +
> +void dcp_pm_complete(struct device *vdev_dev)
> +{
> +     struct dcp_drv *drv = vdev_dev ?
> +             dev_to_virtio(vdev_dev)->priv : NULL;
> +
> +     if (!drv || !drv->dcp_subsystem_dev)
> +             return;
> +
> +     msm_kms_pm_complete(&drv->dcp_subsystem_dev->dev);
> +}
> +
> +int dcp_component_register(struct dcp_drv *drv)
> +{
> +     struct device *dev = &drv->dcp_subsystem_dev->dev;
> +     struct component_match *match = NULL;
> +     int ret;
> +
> +     ret = dcp_dpu_kms_init_dsi_bridges(drv->kms, &match);
> +     if (ret) {
> +             dev_err(dev, "DSI host initialization failed: %d\n", ret);
> +             dcp_dpu_kms_cleanup_bridges(drv->kms);
> +             return ret;
> +     }
> +
> +     /* A GPU is optional for the DCP display-only DRM device. */
> +     msm_add_gpu_components(dev, &match);

Missign error handling.

> +
> +     ret = component_master_add_with_match(dev, &msm_drm_ops, match);
> +     if (ret) {
> +             dev_err(dev, "component_master_add_with_match failed: %d\n",
> +                     ret);
> +             dcp_dpu_kms_cleanup_bridges(drv->kms);
> +             return ret;
> +     }
> +
> +     return 0;
> +}
> +
> +void dcp_component_unregister(struct dcp_drv *drv)
> +{
> +     struct device *dev = &drv->dcp_subsystem_dev->dev;
> +
> +     component_master_del(dev, &msm_drm_ops);
> +     dcp_dpu_kms_cleanup_bridges(drv->kms);
> +}
> +
> +static int dcp_panic_notifier_cb(struct notifier_block *nb,
> +                              unsigned long action, void *data)
> +{
> +     struct dcp_drv *drv = container_of(nb, struct dcp_drv, panic_notifier);
> +
> +     if (drv->hfi)
> +             atomic_set(&drv->hfi->shutdown_in_progress, 1);
> +
> +     return NOTIFY_OK;
> +}
> +
> +void dcp_panic_notifier_register(struct dcp_drv *drv)
> +{
> +     drv->panic_notifier.notifier_call = dcp_panic_notifier_cb;
> +     atomic_notifier_chain_register(&panic_notifier_list, 
> &drv->panic_notifier);
> +}
> +
> +void dcp_panic_notifier_unregister(struct dcp_drv *drv)
> +{
> +     atomic_notifier_chain_unregister(&panic_notifier_list, 
> &drv->panic_notifier);
> +}
> +
> +void __init msm_dcp_register(void)
> +{
> +     dcp_virtio_register();
> +}
> +
> +void __exit msm_dcp_unregister(void)
> +{
> +     dcp_virtio_unregister();
> +}
> diff --git a/drivers/gpu/drm/msm/dcp/dcp_drv.h 
> b/drivers/gpu/drm/msm/dcp/dcp_drv.h
> index 16f87035cb9a..3adc5855a9a2 100644
> --- a/drivers/gpu/drm/msm/dcp/dcp_drv.h
> +++ b/drivers/gpu/drm/msm/dcp/dcp_drv.h
> @@ -14,6 +14,7 @@
>  #include "dcp_ipcc.h"
>  
>  struct dcp_dpu_kms;
> +struct component_match;
>  
>  struct dcp_drv {
>       struct virtio_device    *vdev;
> @@ -24,6 +25,22 @@ struct dcp_drv {
>       struct dcp_dpu_kms      *kms;
>       struct dcp_caps          caps;
>       struct notifier_block    panic_notifier;
> +     struct dcp_ipcc         *ipcc;
>  };
>  
> +int dcp_subsystem_dev_init(struct dcp_drv *drv);
> +void dcp_subsystem_dev_deinit(struct dcp_drv *drv);
> +
> +int dcp_component_register(struct dcp_drv *drv);
> +void dcp_component_unregister(struct dcp_drv *drv);
> +
> +int dcp_pm_prepare(struct device *vdev_dev);
> +void dcp_pm_complete(struct device *vdev_dev);
> +
> +void dcp_panic_notifier_register(struct dcp_drv *drv);
> +void dcp_panic_notifier_unregister(struct dcp_drv *drv);
> +
> +void __init msm_dcp_register(void);
> +void __exit msm_dcp_unregister(void);
> +
>  #endif /* __DCP_DRV_H__ */
> diff --git a/drivers/gpu/drm/msm/dcp/dcp_virtio.c 
> b/drivers/gpu/drm/msm/dcp/dcp_virtio.c
> new file mode 100644
> index 000000000000..15d5caf02ff5
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/dcp/dcp_virtio.c
> @@ -0,0 +1,258 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * DCP VirtIO device driver.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/virtio.h>
> +#include <linux/virtio_config.h>
> +#include <linux/slab.h>
> +
> +#include "dcp_drv.h"
> +#include "dcp_dpu_kms.h"
> +#include "dcp_hfi.h"
> +#include "dcp_ipcc.h"
> +#include "dcp_virtio.h"
> +#include "msm_drv.h"
> +#include "msm_kms.h"
> +
> +static void dcp_virtio_hfi_cleanup(struct dcp_drv *drv);
> +
> +static const unsigned int dcp_virtio_features[] = {
> +     VIRTIO_F_VERSION_1,
> +     VIRTIO_F_NOTIFICATION_DATA,
> +     VIRTIO_F_RING_RESET,
> +     VIRTIO_F_ACCESS_PLATFORM,
> +};
> +
> +/*
> + * The VirtIO core owns transport discovery. This driver owns HFI setup and
> + * creates the DRM component only after firmware capabilities are available.
> + */
> +static int dcp_virtio_probe(struct virtio_device *vdev)
> +{
> +     struct dcp_drv *drv;
> +     struct virtqueue *vqs[DCP_NUM_VQS];
> +     struct virtqueue_info vqs_info[DCP_NUM_VQS] = {
> +             [DCP_VQ_CMD]  = { .name = "cmd",  .callback = 
> dcp_hfi_cmd_callback },
> +             [DCP_VQ_RESP] = { .name = "resp", .callback = 
> dcp_hfi_resp_callback },
> +     };
> +     struct dcp_dpu_kms *dcp_kms;
> +     struct msm_drm_private *priv;
> +     int ret;
> +
> +     dev_dbg(&vdev->dev, "DCP VirtIO probe started\n");
> +
> +     drv = devm_kzalloc(&vdev->dev, sizeof(*drv), GFP_KERNEL);
> +     if (!drv)
> +             return -ENOMEM;
> +
> +     drv->vdev = vdev;
> +     vdev->priv = drv;
> +
> +     if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
> +             dev_err(&vdev->dev, "VIRTIO_F_VERSION_1 not negotiated\n");
> +             return -ENODEV;
> +     }
> +
> +     drv->ipcc = dcp_virtio_get_ipcc(vdev);

Here you are breaking the abstraction boundary. The DCP is a VirtIO
device. You should not use IPCC to communicate with it.

> +     /* Access-platform is required for the firmware-visible IOVA mappings. 
> */
> +     if (!virtio_has_feature(vdev, VIRTIO_F_ACCESS_PLATFORM)) {
> +             dev_err(&vdev->dev, "VIRTIO_F_ACCESS_PLATFORM not 
> negotiated\n");
> +             return -ENODEV;
> +     }
> +
> +     ret = dcp_subsystem_dev_init(drv);
> +     if (ret)
> +             return ret;
> +
> +     ret = virtio_find_vqs(vdev, DCP_NUM_VQS, vqs, vqs_info, NULL);
> +     if (ret) {
> +             dev_err(&vdev->dev, "virtqueue allocation failed: %d\n", ret);
> +             goto err_fn_dev;
> +     }
> +
> +     ret = dcp_hfi_init(drv, vdev, vqs[DCP_VQ_CMD], vqs[DCP_VQ_RESP],
> +                        vdev->dev.parent);
> +     if (ret) {
> +             dev_err(&vdev->dev, "HFI init failed: %d\n", ret);
> +             goto err_del_vqs;
> +     }
> +
> +     dcp_ipcc_set_resp_vq(drv->ipcc, vqs[DCP_VQ_RESP]);
> +
> +     /*
> +      * Keep the device unready until HFI state and virtqueues are 
> initialized.
> +      * KMS registration below depends on synchronous firmware 
> initialization.
> +      */
> +     virtio_device_ready(vdev);
> +     virtqueue_kick(drv->hfi->resp_vq);
> +
> +     ret = dcp_hfi_send_device_init(drv->hfi);
> +     if (ret) {
> +             dev_err(&vdev->dev, "HFI DEVICE_INIT failed: %d\n", ret);
> +             goto err_hfi_deinit;
> +     }
> +
> +     ret = dcp_hfi_get_capabilities(drv->hfi, &drv->caps);
> +     if (ret) {
> +             dev_err(&vdev->dev, "HFI GET_CAPS failed: %d\n", ret);
> +             goto err_hfi_deinit;
> +     }
> +
> +     /* Register the display resources before exposing the DRM component. */
> +     ret = dcp_hfi_send_resource_register(drv->hfi);
> +     if (ret) {
> +             dev_err(&vdev->dev, "HFI RESOURCE_REGISTER failed: %d\n", ret);
> +             goto err_hfi_deinit;
> +     }
> +
> +     dev_dbg(&vdev->dev,
> +             "DCP caps: %u displays, max %ux%u, %u planes\n",
> +             drv->caps.num_displays, drv->caps.max_width, 
> drv->caps.max_height,
> +             drv->caps.max_planes);
> +
> +     dcp_kms = devm_kzalloc(&drv->dcp_subsystem_dev->dev, sizeof(*dcp_kms), 
> GFP_KERNEL);
> +     if (!dcp_kms) {
> +             ret = -ENOMEM;
> +             goto err_hfi_deinit;
> +     }
> +
> +     dcp_kms->drv       = drv;
> +     dcp_kms->pm_dev    = &drv->dcp_subsystem_dev->dev;
> +     dcp_kms->hfi       = drv->hfi;
> +     dcp_kms->caps      = &drv->caps;
> +     dcp_kms->dpus_np   = drv->dcp_subsystem_node;
> +     dcp_kms->iommu_dev = &drv->dcp_subsystem_dev->dev;
> +     drv->kms        = dcp_kms;
> +
> +     ret = msm_kms_init(&dcp_kms->base, &dcp_dpu_kms_funcs);
> +     if (ret) {
> +             dev_err(&vdev->dev, "msm_kms_init failed: %d\n", ret);
> +             goto err_hfi_deinit;
> +     }
> +
> +     priv = devm_kzalloc(&drv->dcp_subsystem_dev->dev, sizeof(*priv), 
> GFP_KERNEL);
> +     if (!priv) {
> +             ret = -ENOMEM;
> +             goto err_hfi_deinit;
> +     }
> +
> +     priv->kms      = &dcp_kms->base;
> +     priv->kms_init = dcp_kms_init;
> +     dev_set_drvdata(&drv->dcp_subsystem_dev->dev, priv);
> +     dcp_kms->rpm_enabled = true;
> +
> +     /* Component binding now sees initialized HFI, capabilities, and IOMMU 
> state. */
> +     ret = dcp_component_register(drv);
> +     if (ret) {
> +             dev_err_probe(&vdev->dev, ret, "component register failed\n");
> +             goto err_hfi_deinit;
> +     }
> +
> +     dcp_panic_notifier_register(drv);
> +
> +     dev_dbg(&vdev->dev, "DCP VirtIO probe complete\n");
> +     return 0;
> +
> +err_hfi_deinit:
> +     dcp_virtio_hfi_cleanup(drv);
> +     goto err_fn_dev;
> +err_del_vqs:
> +     virtio_reset_device(vdev);
> +     vdev->config->del_vqs(vdev);
> +err_fn_dev:
> +     dcp_subsystem_dev_deinit(drv);
> +     return ret;
> +}
> +
> +static void dcp_virtio_hfi_cleanup(struct dcp_drv *drv)
> +{
> +     struct virtio_device *vdev = drv->vdev;
> +
> +     if (!drv->hfi)
> +             return;
> +
> +     dcp_ipcc_set_resp_vq(drv->ipcc, NULL);
> +
> +     dcp_hfi_stop(drv->hfi);
> +     virtio_reset_device(vdev);
> +     virtio_synchronize_cbs(vdev);
> +     dcp_hfi_quiesce_queues(drv->hfi);
> +     vdev->config->del_vqs(vdev);
> +     dcp_hfi_deinit(drv->hfi);
> +}
> +
> +/* Remove DRM users before tearing down HFI, IPCC, or the VirtIO queues. */
> +static void dcp_virtio_remove(struct virtio_device *vdev)
> +{
> +     struct dcp_drv *drv = vdev->priv;
> +
> +     dev_dbg(&vdev->dev, "DCP VirtIO remove\n");
> +
> +     dcp_component_unregister(drv);
> +     dcp_panic_notifier_unregister(drv);
> +
> +     dcp_virtio_hfi_cleanup(drv);
> +
> +     dcp_subsystem_dev_deinit(drv);
> +}
> +
> +/* KMS shutdown must complete while the firmware transport is available. */
> +static void dcp_virtio_shutdown(struct virtio_device *vdev)
> +{
> +     struct dcp_drv *drv = vdev->priv;
> +
> +     pm_runtime_get_sync(&drv->dcp_subsystem_dev->dev);
> +     msm_kms_shutdown(drv->dcp_subsystem_dev);
> +     pm_runtime_put_noidle(&drv->dcp_subsystem_dev->dev);
> +}
> +
> +static const struct virtio_device_id dcp_virtio_id_table[] = {
> +     { VIRTIO_ID_QPSFI, VIRTIO_VENDOR_ID_DCP_HFI },

What exactly does it mean? Are you using Vendor ID (which should be
Qualcomm) to distinguish between possible QPSFI devices?

> +     { 0 },
> +};
> +MODULE_DEVICE_TABLE(virtio, dcp_virtio_id_table);
> +
> +static const struct dev_pm_ops dcp_virtio_pm_ops = {
> +     .prepare = dcp_pm_prepare,
> +     .complete = dcp_pm_complete,
> +};
> +
> +static struct virtio_driver dcp_virtio_driver = {
> +     .driver = {
> +             .name  = "qcom-dcp-hfi",
> +             .owner = THIS_MODULE,
> +             .pm    = &dcp_virtio_pm_ops,
> +     },
> +     .id_table           = dcp_virtio_id_table,
> +     .feature_table      = dcp_virtio_features,
> +     .feature_table_size = ARRAY_SIZE(dcp_virtio_features),
> +     .probe              = dcp_virtio_probe,
> +     .remove             = dcp_virtio_remove,
> +     .shutdown           = dcp_virtio_shutdown,
> +};
> +
> +int dcp_virtio_register(void)
> +{
> +     int ret;
> +
> +     ret = dcp_virtio_transport_register();
> +     if (ret)
> +             return ret;
> +
> +     ret = register_virtio_driver(&dcp_virtio_driver);
> +     if (ret)
> +             dcp_virtio_transport_unregister();
> +
> +     return ret;
> +}
> +
> +void dcp_virtio_unregister(void)
> +{
> +     unregister_virtio_driver(&dcp_virtio_driver);
> +     dcp_virtio_transport_unregister();
> +}
> diff --git a/drivers/gpu/drm/msm/dcp/dcp_virtio.h 
> b/drivers/gpu/drm/msm/dcp/dcp_virtio.h
> index a9c3b9aff61d..3ded8293ab18 100644
> --- a/drivers/gpu/drm/msm/dcp/dcp_virtio.h
> +++ b/drivers/gpu/drm/msm/dcp/dcp_virtio.h
> @@ -8,9 +8,11 @@
>  
>  #include <linux/device.h>
>  #include <linux/virtio.h>
> +#include <linux/virtio_ids.h>
>  
>  struct dcp_drv;
>  struct dcp_ipcc;
> +#define VIRTIO_VENDOR_ID_DCP_HFI             1

Squatting the ID?

>  
>  struct dcp_ipcc *dcp_virtio_get_ipcc(struct virtio_device *vdev);
>  
> diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
> index 5e8f3ce26b32..5816c64d7ce7 100644
> --- a/drivers/gpu/drm/msm/msm_drv.c
> +++ b/drivers/gpu/drm/msm/msm_drv.c
> @@ -1093,8 +1093,8 @@ static const struct of_device_id msm_gpu_match[] = {
>       { },
>  };
>  
> -static int add_gpu_components(struct device *dev,
> -                           struct component_match **matchptr)
> +int msm_add_gpu_components(struct device *dev,
> +                        struct component_match **matchptr)

Separate commit.

>  {
>       struct device_node *np;
>  
> @@ -1153,7 +1153,7 @@ int msm_drv_probe(struct device *master_dev,
>       }
>  
>       if (!msm_separate_gpu_kms_components()) {
> -             ret = add_gpu_components(master_dev, &match);
> +             ret = msm_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 2840e8a5052d..aa5dfd82ac6f 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -523,6 +523,8 @@ static inline unsigned long timeout_to_jiffies(const 
> ktime_t *timeout)
>  /* Driver helpers */
>  
>  extern const struct component_master_ops msm_drm_ops;
> +int msm_add_gpu_components(struct device *dev,
> +                        struct component_match **matchptr);
>  
>  int msm_kms_pm_prepare(struct device *dev);
>  void msm_kms_pm_complete(struct device *dev);
> 
> -- 
> 2.43.0
> 

-- 
With best wishes
Dmitry

Reply via email to