Browse Source

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 <[email protected]>
Jeykumar Sankaran 5 years ago
parent
commit
99df0d5052
5 changed files with 139 additions and 0 deletions
  1. 61 0
      include/linux/sde_vm_event.h
  2. 1 0
      msm/Makefile
  3. 15 0
      msm/msm_drv.c
  4. 4 0
      msm/msm_drv.h
  5. 58 0
      msm/sde_vm_event.c

+ 61 - 0
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 <linux/list.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <drm/drm_device.h>
+
+/**
+ * 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__

+ 1 - 0
msm/Makefile

@@ -48,6 +48,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
 	sde/sde_color_processing.o \
 	sde/sde_color_processing.o \
 	sde/sde_vbif.o \
 	sde/sde_vbif.o \
 	sde_io_util.o \
 	sde_io_util.o \
+	sde_vm_event.o \
 	sde/sde_hw_reg_dma_v1_color_proc.o \
 	sde/sde_hw_reg_dma_v1_color_proc.o \
 	sde/sde_hw_color_proc_v4.o \
 	sde/sde_hw_color_proc_v4.o \
 	sde/sde_hw_ad4.o \
 	sde/sde_hw_ad4.o \

+ 15 - 0
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 drm_device *ddev = platform_get_drvdata(pdev);
 	struct msm_drm_private *priv = ddev->dev_private;
 	struct msm_drm_private *priv = ddev->dev_private;
 	struct msm_kms *kms = priv->kms;
 	struct msm_kms *kms = priv->kms;
+	struct msm_vm_client_entry *client_entry, *tmp;
 	int i;
 	int i;
 
 
 	/* We must cancel and cleanup any pending vblank enable/disable
 	/* 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);
 	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);
 	msm_mdss_destroy(ddev);
 
 
 	ddev->dev_private = NULL;
 	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->client_event_list);
 	INIT_LIST_HEAD(&priv->inactive_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: */
 	/* Bind all our sub-components: */
 	ret = msm_component_bind_all(dev, ddev);
 	ret = msm_component_bind_all(dev, ddev);

+ 4 - 0
msm/msm_drv.h

@@ -34,6 +34,7 @@
 #include <linux/of_graph.h>
 #include <linux/of_graph.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/sde_io_util.h>
 #include <linux/sde_io_util.h>
+#include <linux/sde_vm_event.h>
 #include <linux/sizes.h>
 #include <linux/sizes.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
 
 
@@ -922,6 +923,9 @@ struct msm_drm_private {
 
 
 	/* update the flag when msm driver receives shutdown notification */
 	/* update the flag when msm driver receives shutdown notification */
 	bool shutdown_in_progress;
 	bool shutdown_in_progress;
+
+	struct mutex vm_client_lock;
+	struct list_head vm_client_list;
 };
 };
 
 
 /* get struct msm_kms * from drm_device * */
 /* get struct msm_kms * from drm_device * */

+ 58 - 0
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 <linux/sde_vm_event.h>
+#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);