diff --git a/include/linux/sde_vm_event.h b/include/linux/sde_vm_event.h new file mode 100644 index 000000000000..04cd6eed6eec --- /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 952746f5f5da..a4fd8a710f37 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 9071fa2d8823..9eb1590540fc 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 55ea0f1c42fb..356fb6404ce1 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 000000000000..f0a571159e0f --- /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);