From 99df0d50529198dd7b43c700b9ede17814e3baf1 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran Date: Thu, 21 May 2020 10:38:53 -0700 Subject: [PATCH] disp: msm: add support for vm event register framework Besides SDE, other subdrivers may be interested in participating in the VM switch. This change provides framework for display dependent drivers like DSI, DP and RSCC to register for various VM switch event hooks. The following hooks to provided through msm_vm_ops: post_hw_acquire: invoked before the first frame push after gaining HW access. pre_hw_release: invoked after the last frame commit before releasing the HW. check: check with vm clients for their readiness for HW releasing. Change-Id: I616db04e979f78f76f6f97ee3b068dd348339ab6 Signed-off-by: Jeykumar Sankaran --- include/linux/sde_vm_event.h | 61 ++++++++++++++++++++++++++++++++++++ msm/Makefile | 1 + msm/msm_drv.c | 15 +++++++++ msm/msm_drv.h | 4 +++ msm/sde_vm_event.c | 58 ++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 include/linux/sde_vm_event.h create mode 100644 msm/sde_vm_event.c diff --git a/include/linux/sde_vm_event.h b/include/linux/sde_vm_event.h new file mode 100644 index 0000000000..04cd6eed6e --- /dev/null +++ b/include/linux/sde_vm_event.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_VM_EVENT_H__ +#define __SDE_VM_EVENT_H__ + +#include +#include +#include +#include +#include + +/** + * struct msm_vm_ops - hooks for communication with vm clients + * @vm_pre_hw_release: invoked before releasing the HW + * @vm_post_hw_acquire: invoked before pushing the first commit + * @vm_check: invoked to check the readiness of the vm_clients + * before releasing the HW + */ +struct msm_vm_ops { + int (*vm_pre_hw_release)(void *priv_data); + int (*vm_post_hw_acquire)(void *priv_data); + int (*vm_check)(void *priv_data); +}; + +/** + * msm_vm_client_entry - defines the vm client info + * @ops: client vm_ops + * @dev: clients device id. Used in unregister + * @data: client custom data + * @list: linked list entry + */ +struct msm_vm_client_entry { + struct msm_vm_ops ops; + struct device *dev; + void *data; + struct list_head list; +}; + +/** + * msm_register_vm_event - api for display dependent drivers(clients) to + * register for vm events + * @dev: msm device + * @client_dev: client device + * @ops: vm event hooks + * @priv_data: client custom data + */ +int msm_register_vm_event(struct device *dev, struct device *client_dev, + struct msm_vm_ops *ops, void *priv_data); + +/** + * msm_unregister_vm_event - api for display dependent drivers(clients) to + * unregister from vm events + * @dev: msm device + * @client_dev: client device + */ +void msm_unregister_vm_event(struct device *dev, struct device *client_dev); + +#endif //__SDE_VM_EVENT_H__ diff --git a/msm/Makefile b/msm/Makefile index 952746f5f5..a4fd8a710f 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -48,6 +48,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_color_processing.o \ sde/sde_vbif.o \ sde_io_util.o \ + sde_vm_event.o \ sde/sde_hw_reg_dma_v1_color_proc.o \ sde/sde_hw_color_proc_v4.o \ sde/sde_hw_ad4.o \ diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 9071fa2d88..9eb1590540 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -394,6 +394,7 @@ static int msm_drm_uninit(struct device *dev) struct drm_device *ddev = platform_get_drvdata(pdev); struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = priv->kms; + struct msm_vm_client_entry *client_entry, *tmp; int i; /* We must cancel and cleanup any pending vblank enable/disable @@ -455,6 +456,17 @@ static int msm_drm_uninit(struct device *dev) sde_power_resource_deinit(pdev, &priv->phandle); + mutex_lock(&priv->vm_client_lock); + + /* clean up any unregistered clients */ + list_for_each_entry_safe(client_entry, tmp, &priv->vm_client_list, + list) { + list_del(&client_entry->list); + kfree(client_entry); + } + + mutex_unlock(&priv->vm_client_lock); + msm_mdss_destroy(ddev); ddev->dev_private = NULL; @@ -831,6 +843,9 @@ static int msm_drm_component_init(struct device *dev) INIT_LIST_HEAD(&priv->client_event_list); INIT_LIST_HEAD(&priv->inactive_list); + INIT_LIST_HEAD(&priv->vm_client_list); + + mutex_init(&priv->vm_client_lock); /* Bind all our sub-components: */ ret = msm_component_bind_all(dev, ddev); diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 55ea0f1c42..356fb6404c 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -922,6 +923,9 @@ struct msm_drm_private { /* update the flag when msm driver receives shutdown notification */ bool shutdown_in_progress; + + struct mutex vm_client_lock; + struct list_head vm_client_list; }; /* get struct msm_kms * from drm_device * */ diff --git a/msm/sde_vm_event.c b/msm/sde_vm_event.c new file mode 100644 index 0000000000..f0a571159e --- /dev/null +++ b/msm/sde_vm_event.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include "msm_drv.h" + +int msm_register_vm_event(struct device *dev, struct device *client_dev, + struct msm_vm_ops *ops, void *priv_data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = ddev->dev_private; + struct msm_vm_client_entry *client_entry; + + if (!client_dev || !ops) + return -EINVAL; + + client_entry = kzalloc(sizeof(*client_entry), GFP_KERNEL); + if (!client_entry) + return -ENOMEM; + + mutex_lock(&priv->vm_client_lock); + + memcpy(&client_entry->ops, ops, sizeof(*ops)); + client_entry->dev = client_dev; + client_entry->data = priv_data; + + list_add(&client_entry->list, &priv->vm_client_list); + + mutex_unlock(&priv->vm_client_lock); + + return 0; +} +EXPORT_SYMBOL(msm_register_vm_event); + +void msm_unregister_vm_event(struct device *dev, struct device *client_dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = ddev->dev_private; + struct msm_vm_client_entry *client_entry, *tmp; + + mutex_lock(&priv->vm_client_lock); + + list_for_each_entry_safe(client_entry, tmp, &priv->vm_client_list, + list) { + if (client_entry->dev == client_dev) { + list_del(&client_entry->list); + kfree(client_entry); + break; + } + } + + mutex_unlock(&priv->vm_client_lock); +} +EXPORT_SYMBOL(msm_unregister_vm_event);