浏览代码

Merge "disp: msm: sde: parse property for max concurrent TUI displays"

qctecmdr 5 年之前
父节点
当前提交
0ea5003877

+ 6 - 1
include/linux/sde_io_util.h

@@ -85,7 +85,12 @@ struct dss_module_power {
 int msm_dss_ioremap_byname(struct platform_device *pdev,
 	struct dss_io_data *io_data, const char *name);
 void msm_dss_iounmap(struct dss_io_data *io_data);
-
+int msm_dss_get_io_mem(struct platform_device *pdev,
+		       struct list_head *mem_list);
+void msm_dss_clean_io_mem(struct list_head *mem_list);
+int msm_dss_get_io_irq(struct platform_device *pdev,
+		       struct list_head *irq_list, u32 label);
+void msm_dss_clean_io_irq(struct list_head *irq_list);
 int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
 int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
 

+ 97 - 0
include/linux/sde_vm_event.h

@@ -0,0 +1,97 @@
+/* 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_io_irq_entry - define irq item
+ * @label: hh_irq_label for the irq
+ * @irq_num: linux mapped irq num
+ * @list: list head pointer
+ */
+struct msm_io_irq_entry {
+	u32 label;
+	u32 irq_num;
+	struct list_head list;
+};
+
+/**
+ * struct - msm_io_mem_entry - define io memory item
+ * @base: reg base
+ * @size: size of the reg range
+ * @list: list head pointer
+ */
+struct msm_io_mem_entry {
+	phys_addr_t base;
+	phys_addr_t size;
+	struct list_head list;
+};
+
+/**
+ * struct - msm_io_res - represents the hw resources for vm sharing
+ * @irq: list of IRQ's of all the dislay sub-devices
+ * @mem: list of IO memory ranges of all the display sub-devices
+ */
+struct msm_io_res {
+	struct list_head irq;
+	struct list_head mem;
+};
+
+/**
+ * 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
+ * @vm_get_io_resources: invoked to collect HW resources
+ */
+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);
+	int (*vm_get_io_resources)(struct msm_io_res *io_res, 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_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 \

+ 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 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);

+ 4 - 0
msm/msm_drv.h

@@ -34,6 +34,7 @@
 #include <linux/of_graph.h>
 #include <linux/of_device.h>
 #include <linux/sde_io_util.h>
+#include <linux/sde_vm_event.h>
 #include <linux/sizes.h>
 #include <linux/kthread.h>
 
@@ -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 * */

+ 8 - 8
msm/sde/sde_encoder.c

@@ -1342,7 +1342,7 @@ static int _sde_encoder_update_rsc_client(
 	return ret;
 }
 
-static void _sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable)
+void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable)
 {
 	struct sde_encoder_virt *sde_enc;
 	int i;
@@ -1452,7 +1452,7 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
 		}
 
 		/* enable all the irq */
-		_sde_encoder_irq_control(drm_enc, true);
+		sde_encoder_irq_control(drm_enc, true);
 
 		_sde_encoder_pm_qos_add_request(drm_enc);
 
@@ -1460,7 +1460,7 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
 		_sde_encoder_pm_qos_remove_request(drm_enc);
 
 		/* disable all the irq */
-		_sde_encoder_irq_control(drm_enc, false);
+		sde_encoder_irq_control(drm_enc, false);
 
 		/* disable DSI clks */
 		sde_connector_clk_ctrl(sde_enc->cur_master->connector, false);
@@ -1627,7 +1627,7 @@ static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc,
 	}
 
 	if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
-		_sde_encoder_irq_control(drm_enc, true);
+		sde_encoder_irq_control(drm_enc, true);
 	} else {
 		/* enable all the clks and resources */
 		ret = _sde_encoder_resource_control_helper(drm_enc,
@@ -1664,7 +1664,7 @@ static int _sde_encoder_rc_pre_stop(struct drm_encoder *drm_enc,
 
 	if (is_vid_mode &&
 		  sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
-		_sde_encoder_irq_control(drm_enc, true);
+		sde_encoder_irq_control(drm_enc, true);
 	}
 	/* skip if is already OFF or IDLE, resources are off already */
 	else if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF ||
@@ -1781,7 +1781,7 @@ static int _sde_encoder_rc_pre_modeset(struct drm_encoder *drm_enc,
 		goto end;
 	}
 
-	_sde_encoder_irq_control(drm_enc, false);
+	sde_encoder_irq_control(drm_enc, false);
 	_sde_encoder_modeset_helper_locked(drm_enc, sw_event);
 
 	SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
@@ -1819,7 +1819,7 @@ static int _sde_encoder_rc_post_modeset(struct drm_encoder *drm_enc,
 	}
 
 	_sde_encoder_modeset_helper_locked(drm_enc, sw_event);
-	_sde_encoder_irq_control(drm_enc, true);
+	sde_encoder_irq_control(drm_enc, true);
 
 	_sde_encoder_update_rsc_client(drm_enc, true);
 
@@ -1863,7 +1863,7 @@ static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc,
 	}
 
 	if (is_vid_mode) {
-		_sde_encoder_irq_control(drm_enc, false);
+		sde_encoder_irq_control(drm_enc, false);
 	} else {
 		/* disable all the clks and resources */
 		_sde_encoder_update_rsc_client(drm_enc, false);

+ 7 - 0
msm/sde/sde_encoder.h

@@ -525,6 +525,13 @@ void sde_encoder_needs_hw_reset(struct drm_encoder *enc);
  */
 void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable);
 
+/**
+ * sde_encoder_irq_control - control enable/disable of IRQ's
+ * @drm_enc:	Pointer to drm encoder structure
+ * @enable: enable/disable flag
+ */
+void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable);
+
 /**
  * sde_encoder_get_kms - retrieve the kms from encoder
  * @drm_enc:    Pointer to drm encoder structure

+ 5 - 0
msm/sde/sde_hw_catalog.c

@@ -202,6 +202,7 @@ enum sde_prop {
 	SEC_SID_MASK,
 	BASE_LAYER,
 	TRUSTED_VM_ENV,
+	MAX_TRUSTED_VM_DISPLAYS,
 	SDE_PROP_MAX,
 };
 
@@ -574,6 +575,8 @@ static struct sde_prop_type sde_prop[] = {
 	{SEC_SID_MASK, "qcom,sde-secure-sid-mask", false, PROP_TYPE_U32_ARRAY},
 	{BASE_LAYER, "qcom,sde-mixer-stage-base-layer", false, PROP_TYPE_BOOL},
 	{TRUSTED_VM_ENV, "qcom,sde-trusted-vm-env", false, PROP_TYPE_BOOL},
+	{MAX_TRUSTED_VM_DISPLAYS, "qcom,sde-max-trusted-vm-displays", false,
+			PROP_TYPE_U32},
 };
 
 static struct sde_prop_type sde_perf_prop[] = {
@@ -3752,6 +3755,8 @@ static void _sde_top_parse_dt_helper(struct sde_mdss_cfg *cfg,
 			 QSEED_HW_VERSION, 0);
 	cfg->trusted_vm_env = PROP_VALUE_ACCESS(props->values, TRUSTED_VM_ENV,
 			 0);
+	cfg->max_trusted_vm_displays = PROP_VALUE_ACCESS(props->values,
+			MAX_TRUSTED_VM_DISPLAYS, 0);
 }
 
 static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)

+ 3 - 0
msm/sde/sde_hw_catalog.h

@@ -1364,6 +1364,8 @@ struct sde_perf_cfg {
  *
  * @trusted_vm_env	set to true, if the driver is executing in
  *			the trusted VM. false, otherwise.
+ * @max_trusted_vm_displays	maximum number of concurrent trusted
+ *				vm displays supported.
  * @max_sspp_linewidth max source pipe line width support.
  * @vig_sspp_linewidth max vig source pipe line width support.
  * @scaling_linewidth max vig source pipe linewidth for scaling usecases
@@ -1438,6 +1440,7 @@ struct sde_perf_cfg {
 struct sde_mdss_cfg {
 	u32 hwversion;
 	bool trusted_vm_env;
+	u32 max_trusted_vm_displays;
 
 	u32 max_sspp_linewidth;
 	u32 vig_sspp_linewidth;

+ 23 - 2
msm/sde/sde_kms.c

@@ -52,6 +52,7 @@
 #include <linux/qcom_scm.h>
 #include "soc/qcom/secure_buffer.h"
 #include <linux/qtee_shmbridge.h>
+#include <linux/haven/hh_irq_lend.h>
 
 #define CREATE_TRACE_POINTS
 #include "sde_trace.h"
@@ -349,7 +350,7 @@ static int _sde_kms_scm_call(struct sde_kms *sde_kms, int vmid)
 	set_dma_ops(&dummy, NULL);
 
 	dma_handle = dma_map_single(&dummy, sec_sid,
-				num_sids *sizeof(uint32_t), DMA_TO_DEVICE);
+				num_sids * sizeof(uint32_t), DMA_TO_DEVICE);
 	if (dma_mapping_error(&dummy, dma_handle)) {
 		SDE_ERROR("dma_map_single for dummy dev failed vmid 0x%x\n",
 									vmid);
@@ -367,7 +368,7 @@ static int _sde_kms_scm_call(struct sde_kms *sde_kms, int vmid)
 			vmid, qtee_en, num_sids, ret);
 
 	dma_unmap_single(&dummy, dma_handle,
-				num_sids *sizeof(uint32_t), DMA_TO_DEVICE);
+				num_sids * sizeof(uint32_t), DMA_TO_DEVICE);
 
 map_error:
 	if (qtee_en)
@@ -3601,6 +3602,26 @@ power_error:
 	return rc;
 }
 
+int sde_kms_get_io_resources(struct sde_kms *sde_kms, struct msm_io_res *io_res)
+{
+	struct platform_device *pdev = to_platform_device(sde_kms->dev->dev);
+	int rc = 0;
+
+	rc = msm_dss_get_io_mem(pdev, &io_res->mem);
+	if (rc) {
+		SDE_ERROR("failed to get io mem for KMS, rc = %d\n", rc);
+		return rc;
+	}
+
+	rc = msm_dss_get_io_irq(pdev, &io_res->irq, HH_IRQ_LABEL_SDE);
+	if (rc) {
+		SDE_ERROR("failed to get io irq for KMS");
+		return rc;
+	}
+
+	return rc;
+}
+
 static int sde_kms_hw_init(struct msm_kms *kms)
 {
 	struct sde_kms *sde_kms;

+ 8 - 0
msm/sde/sde_kms.h

@@ -691,4 +691,12 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder);
  */
 void sde_kms_irq_enable_notify(struct sde_kms *sde_kms, bool enable);
 
+/**
+ * sde_kms_get_io_resources() - reads associated register range
+ * @kms: pointer to sde_kms structure
+ * @io_res: pointer to msm_io_res struct to populate the ranges
+ * Return: error code.
+ */
+int sde_kms_get_io_resources(struct sde_kms *kms, struct msm_io_res *io_res);
+
 #endif /* __sde_kms_H__ */

+ 122 - 0
msm/sde_io_util.c

@@ -9,6 +9,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/delay.h>
 #include <linux/sde_io_util.h>
+#include <linux/sde_vm_event.h>
 
 #define MAX_I2C_CMDS  16
 void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
@@ -129,6 +130,127 @@ void msm_dss_iounmap(struct dss_io_data *io_data)
 } /* msm_dss_iounmap */
 EXPORT_SYMBOL(msm_dss_iounmap);
 
+int msm_dss_get_io_mem(struct platform_device *pdev, struct list_head *mem_list)
+{
+	struct list_head temp_head;
+	struct msm_io_mem_entry *io_mem;
+	struct resource *res = NULL;
+	const char *reg_name, *exclude_reg_name;
+	int i, j, rc = 0;
+	int num_entry, num_exclude_entry;
+
+	INIT_LIST_HEAD(&temp_head);
+
+	num_entry = of_property_count_strings(pdev->dev.of_node,
+						  "reg-names");
+	if (num_entry < 0)
+		num_entry = 0;
+
+	/*
+	 * check the dt property to know whether the platform device wants
+	 * to exclude any reg ranges from the IO list
+	 */
+	num_exclude_entry = of_property_count_strings(pdev->dev.of_node,
+					  "qcom,sde-vm-exclude-reg-names");
+	if (num_exclude_entry < 0)
+		num_exclude_entry = 0;
+
+	for (i = 0; i < num_entry; i++) {
+		bool exclude = false;
+
+		of_property_read_string_index(pdev->dev.of_node,
+				"reg-names", i,	&reg_name);
+
+		for (j = 0; j < num_exclude_entry; j++) {
+			of_property_read_string_index(pdev->dev.of_node,
+				"qcom,sde-vm-exclude-reg-names", j,
+				&exclude_reg_name);
+
+			if (!strcmp(reg_name, exclude_reg_name)) {
+				exclude = true;
+				break;
+			}
+		}
+
+		if (exclude)
+			continue;
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   reg_name);
+		if (!res)
+			break;
+
+		io_mem = kzalloc(sizeof(*io_mem), GFP_KERNEL);
+		if (!io_mem) {
+			msm_dss_clean_io_mem(&temp_head);
+			rc = -ENOMEM;
+			goto parse_fail;
+		}
+
+		io_mem->base = res->start;
+		io_mem->size = resource_size(res);
+
+		list_add(&io_mem->list, &temp_head);
+	}
+
+	list_splice(&temp_head, mem_list);
+
+	return 0;
+
+parse_fail:
+	msm_dss_clean_io_mem(&temp_head);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_dss_get_io_mem);
+
+void msm_dss_clean_io_mem(struct list_head *mem_list)
+{
+	struct msm_io_mem_entry *pos, *tmp;
+
+	list_for_each_entry_safe(pos, tmp, mem_list, list) {
+		list_del(&pos->list);
+		kzfree(pos);
+	}
+}
+EXPORT_SYMBOL(msm_dss_clean_io_mem);
+
+int msm_dss_get_io_irq(struct platform_device *pdev, struct list_head *irq_list,
+		       u32 label)
+{
+	struct msm_io_irq_entry *io_irq;
+	int irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		pr_err("invalid IRQ\n");
+		return irq;
+	}
+
+	io_irq = kzalloc(sizeof(*io_irq), GFP_KERNEL);
+	if (!io_irq)
+		return -ENOMEM;
+
+	io_irq->label  = label;
+	io_irq->irq_num = irq;
+
+	list_add(&io_irq->list, irq_list);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_dss_get_io_irq);
+
+void msm_dss_clean_io_irq(struct list_head *irq_list)
+{
+	struct msm_io_irq_entry *pos, *tmp;
+
+	list_for_each_entry_safe(pos, tmp, irq_list, list) {
+		list_del(&pos->list);
+		kzfree(pos);
+	}
+}
+EXPORT_SYMBOL(msm_dss_clean_io_irq);
+
 int msm_dss_get_vreg(struct device *dev, struct dss_vreg *in_vreg,
 	int num_vreg, int enable)
 {

+ 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);