msm: Add GENI Serial Engine Driver

GENI Serial Engine Driver provides helper functions to configure the
operating modes, packing formats and to power on/off the resources
associated with the Serial Engines in Qualcomm Technologies, Inc. Universal
Peripheral(QUPv3) core. This driver aggregates bus voting for multiple
Serial engines within a QUPv3 core. This drivers also programs the IOMMU to
enable Stage 1 translation for multiple bus masters within the QUPv3 core.

CRs-Fixed: 2033414
Change-Id: I011c9c5f711f9d6edee6be99e3e7395bbf747245
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 58e8850..622ccbc 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/qcom-geni-se.h>
@@ -50,9 +51,12 @@
 #define SLV_ADDR_MSK		(GENMASK(15, 9))
 #define SLV_ADDR_SHFT		(9)
 
+#define I2C_CORE2X_VOTE		(10000)
+
 struct geni_i2c_dev {
 	struct device *dev;
 	void __iomem *base;
+	unsigned int tx_wm;
 	int irq;
 	int err;
 	struct i2c_adapter adap;
@@ -61,6 +65,7 @@
 	struct se_geni_rsc i2c_rsc;
 	int cur_wr;
 	int cur_rd;
+	struct device *wrapper_dev;
 };
 
 static inline void qcom_geni_i2c_conf(void __iomem *base, int dfs, int div)
@@ -114,7 +119,7 @@
 		}
 	} else if ((m_stat & M_TX_FIFO_WATERMARK_EN) &&
 					!(cur->flags & I2C_M_RD)) {
-		for (j = 0; j < 0x1f; j++) {
+		for (j = 0; j < gi2c->tx_wm; j++) {
 			u32 temp = 0;
 			int p;
 
@@ -163,9 +168,7 @@
 		pm_runtime_set_suspended(gi2c->dev);
 		return ret;
 	}
-	geni_se_init(gi2c->base, FIFO_MODE, 0xF, 0x10);
 	qcom_geni_i2c_conf(gi2c->base, 0, 2);
-	se_config_packing(gi2c->base, 8, 4, true);
 	dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
 				num, msgs[0].len, msgs[0].flags);
 	for (i = 0; i < num; i++) {
@@ -237,6 +240,8 @@
 {
 	struct geni_i2c_dev *gi2c;
 	struct resource *res;
+	struct platform_device *wrapper_pdev;
+	struct device_node *wrapper_ph_node;
 	int ret;
 
 	gi2c = devm_kzalloc(&pdev->dev, sizeof(*gi2c), GFP_KERNEL);
@@ -249,6 +254,29 @@
 	if (!res)
 		return -EINVAL;
 
+	wrapper_ph_node = of_parse_phandle(pdev->dev.of_node,
+				"qcom,wrapper-core", 0);
+	if (IS_ERR_OR_NULL(wrapper_ph_node)) {
+		ret = PTR_ERR(wrapper_ph_node);
+		dev_err(&pdev->dev, "No wrapper core defined\n");
+		return ret;
+	}
+	wrapper_pdev = of_find_device_by_node(wrapper_ph_node);
+	of_node_put(wrapper_ph_node);
+	if (IS_ERR_OR_NULL(wrapper_pdev)) {
+		ret = PTR_ERR(wrapper_pdev);
+		dev_err(&pdev->dev, "Cannot retrieve wrapper device\n");
+		return ret;
+	}
+	gi2c->wrapper_dev = &wrapper_pdev->dev;
+	gi2c->i2c_rsc.wrapper_dev = &wrapper_pdev->dev;
+	ret = geni_se_resources_init(&gi2c->i2c_rsc, I2C_CORE2X_VOTE,
+				     (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+	if (ret) {
+		dev_err(gi2c->dev, "geni_se_resources_init\n");
+		return ret;
+	}
+
 	gi2c->i2c_rsc.se_clk = devm_clk_get(&pdev->dev, "se-clk");
 	if (IS_ERR(gi2c->i2c_rsc.se_clk)) {
 		ret = PTR_ERR(gi2c->i2c_rsc.se_clk);
@@ -360,6 +388,14 @@
 	if (ret)
 		return ret;
 
+	if (unlikely(!gi2c->tx_wm)) {
+		int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base);
+
+		gi2c->tx_wm = gi2c_tx_depth - 1;
+		geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
+		geni_se_select_mode(gi2c->base, FIFO_MODE);
+		se_config_packing(gi2c->base, 8, 4, true);
+	}
 	enable_irq(gi2c->irq);
 	return 0;
 }