linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ansuel Smith <ansuelsmth@gmail.com>
To: Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Rob Herring <robh+dt@kernel.org>,
	Ansuel Smith <ansuelsmth@gmail.com>,
	linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] drivers: soc: qcom: add TCSR driver
Date: Sat, 22 Jan 2022 01:16:09 +0100	[thread overview]
Message-ID: <20220122001609.15904-3-ansuelsmth@gmail.com> (raw)
In-Reply-To: <20220122001609.15904-1-ansuelsmth@gmail.com>

Add QCOM Top Control and Status Registers driver required to control and
configure various peripherals for ipq8064 and ipq4019. This is required
to configure usb3 mode, gsbi configuration for ipq8064 and various
devices (WiFi, USB mode, WiFi memtype, ESS interface mode) for ipq4019.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/soc/qcom/Kconfig     |   8 ++
 drivers/soc/qcom/Makefile    |   1 +
 drivers/soc/qcom/qcom_tcsr.c | 198 +++++++++++++++++++++++++++++++++++
 3 files changed, 207 insertions(+)
 create mode 100644 drivers/soc/qcom/qcom_tcsr.c

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index e718b8735444..20dd341ae369 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -209,6 +209,14 @@ config QCOM_STATS
 	  various SoC level low power modes statistics and export to debugfs
 	  interface.
 
+config QCOM_TCSR
+	tristate "QCOM Top Control and Status Registers"
+	depends on ARCH_QCOM || COMPILE_TEST
+	select MFD_SYSCON
+	help
+	  Say y here to enable TCSR support. The TCSR provides control
+	  functions for various peripherals (USB, WiFi, ESS).
+
 config QCOM_WCNSS_CTRL
 	tristate "Qualcomm WCNSS control driver"
 	depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 70d5de69fd7b..b17dd46ed1fa 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
 obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
 obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=	kryo-l2-accessors.o
+obj-$(CONFIG_QCOM_TCSR)	 += qcom_tcsr.o
diff --git a/drivers/soc/qcom/qcom_tcsr.c b/drivers/soc/qcom/qcom_tcsr.c
new file mode 100644
index 000000000000..dc80768d57c2
--- /dev/null
+++ b/drivers/soc/qcom/qcom_tcsr.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define TCSR_USB_PORT_SEL_REG			0xb0
+#define TCSR_USB_PORT_SEL_MASK			GENMASK(1, 0)
+
+#define TCSR_USB_SELECT_USB3_P0			FIELD_PREP(TCSR_USB_PORT_SEL_MASK, 0x1)
+#define TCSR_USB_SELECT_USB3_P1			FIELD_PREP(TCSR_USB_PORT_SEL_MASK, 0x2)
+#define TCSR_USB_SELECT_USB3_DUAL		FIELD_PREP(TCSR_USB_PORT_SEL_MASK, 0x3)
+
+/* IPQ40xx HS PHY Mode Select */
+#define TCSR_USB_HSPHY_CONFIG_REG		0xc
+#define TCSR_USB_HSPHY_MODE_MASK		BIT(21)
+#define TCSR_USB_HSPHY_MODE_HOST_MODE		FIELD_PREP(TCSR_USB_HSPHY_MODE_MASK, 0x0)
+#define TCSR_USB_HSPHY_MODE_DEVICE_MODE		FIELD_PREP(TCSR_USB_HSPHY_MODE_MASK, 0x1)
+
+/* IPQ40xx ess interface mode select */
+#define TCSR_ESS_INTERFACE_SEL_REG		0x0
+#define TCSR_ESS_INTERFACE_SEL_MASK		GENMASK(3, 0)
+#define TCSR_ESS_PSGMII				FIELD_PREP(TCSR_ESS_INTERFACE_SEL_MASK, 0x0)
+#define TCSR_ESS_PSGMII_RGMII5			FIELD_PREP(TCSR_ESS_INTERFACE_SEL_MASK, 0x1)
+#define TCSR_ESS_PSGMII_RMII0			FIELD_PREP(TCSR_ESS_INTERFACE_SEL_MASK, 0x2)
+#define TCSR_ESS_PSGMII_RMII1			FIELD_PREP(TCSR_ESS_INTERFACE_SEL_MASK, 0x4)
+#define TCSR_ESS_PSGMII_RMII0_RMII1		FIELD_PREP(TCSR_ESS_INTERFACE_SEL_MASK, 0x6)
+#define TCSR_ESS_PSGMII_RGMII4			FIELD_PREP(TCSR_ESS_INTERFACE_SEL_MASK, 0x9)
+
+/* IPQ40xx WiFi Global Config */
+#define TCSR_WIFI0_GLB_CFG_OFFSET_REG		0x0
+#define TCSR_WIFI1_GLB_CFG_OFFSET_REG		0x4
+/* Enable AXI master bus Axid translating to confirm all txn submitted by order */
+#define TCSR_WIFI_GLB_CFG_AXID_EN		BIT(30)
+/* 1:  use locally generate socslv_wxi_bvalid for performance.
+ * 0:  use SNOC socslv_wxi_bvalid.
+ */
+#define TCSR_WIFI_GLB_CFG_SOCSLV_WXI_BVALID	BIT(24)
+#define TCSR_WIFI_GLB_CFG_SOCSLV_SNOC		FIELD_PREP(TCSR_WIFI_GLB_CFG_SOCSLV_WXI_BVALID, 0x0)
+#define TCSR_WIFI_GLB_CFG_SOCSLV_LOCAL		FIELD_PREP(TCSR_WIFI_GLB_CFG_SOCSLV_WXI_BVALID, 0x1)
+
+/* Configure special wifi memory type needed for some IPQ40xx devices */
+#define TCSR_PNOC_SNOC_MEMTYPE_M0_M2_REG	0x4
+#define TCSR_WIFI_NOC_MEMTYPE_MASK		GENMASK(26, 24)
+#define TCSR_WIFI_NOC_MEMTYPE_M0_M2		FIELD_PREP(TCSR_WIFI_NOC_MEMTYPE_MASK, 0x2)
+
+static int qcom_tcsr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node;
+	struct regmap *tcsr;
+	int ret, val;
+
+	node = dev->of_node;
+	tcsr = syscon_node_to_regmap(node);
+	if (IS_ERR(tcsr))
+		return PTR_ERR(tcsr);
+
+	if (of_find_property(node, "qcom,usb-ctrl-select", NULL) &&
+	    of_device_is_compatible(node, "qcom,tcsr-ipq8064")) {
+		if (of_property_match_string(node, "qcom,usb-ctrl-select",
+					     "p0")) {
+			val = TCSR_USB_SELECT_USB3_P0;
+		} else if (of_property_match_string(node, "qcom,usb-ctrl-select",
+						  "p1")) {
+			val = TCSR_USB_SELECT_USB3_P1;
+		} else if (of_property_match_string(node, "qcom,usb-ctrl-select",
+						  "dual")) {
+			val = TCSR_USB_SELECT_USB3_DUAL;
+		} else {
+			dev_err(dev, "invalid value for qcom,usb-ctrl-select");
+			return -EINVAL;
+		}
+
+		ret = regmap_update_bits(tcsr, TCSR_USB_PORT_SEL_REG,
+					 TCSR_USB_PORT_SEL_MASK, val);
+		if (ret)
+			return ret;
+	}
+
+	if (of_find_property(node, "qcom,usb-hsphy-mode-select", NULL) &&
+	    of_device_is_compatible(node, "qcom,tcsr-ipq4019")) {
+		if (of_property_match_string(node, "qcom,usb-hsphy-mode-select",
+					     "host")) {
+			val = TCSR_USB_HSPHY_MODE_HOST_MODE;
+		} else if (of_property_match_string(node, "qcom,usb-hsphy-mode-select",
+						  "device")) {
+			val = TCSR_USB_HSPHY_MODE_DEVICE_MODE;
+		} else {
+			dev_err(dev, "invalid value for qcom,usb-hsphy-mode-select");
+			return -EINVAL;
+		}
+
+		ret = regmap_update_bits(tcsr, TCSR_USB_HSPHY_CONFIG_REG,
+					 TCSR_USB_HSPHY_MODE_MASK, val);
+		if (ret)
+			return ret;
+	}
+
+	if (of_find_property(node, "qcom,ess-interface-select", NULL) &&
+	    of_device_is_compatible(node, "qcom,tcsr-ipq4019")) {
+		if (of_property_match_string(node, "qcom,ess-interface-select",
+					     "psgmii")) {
+			val = TCSR_ESS_PSGMII;
+		} else if (of_property_match_string(node, "qcom,ess-interface-select",
+						  "rgmii5")) {
+			val = TCSR_ESS_PSGMII_RGMII5;
+		} else if (of_property_match_string(node, "qcom,ess-interface-select",
+						  "rmii0")) {
+			val = TCSR_ESS_PSGMII_RMII0;
+		} else if (of_property_match_string(node, "qcom,ess-interface-select",
+						  "rmii1")) {
+			val = TCSR_ESS_PSGMII_RMII1;
+		} else if (of_property_match_string(node, "qcom,ess-interface-select",
+						  "rmii0_rmii1")) {
+			val = TCSR_ESS_PSGMII_RMII0_RMII1;
+		} else if (of_property_match_string(node, "qcom,ess-interface-select",
+						  "rgmii4")) {
+			val = TCSR_ESS_PSGMII_RGMII4;
+		} else {
+			dev_err(dev, "invalid value for qcom,ess-interface-select");
+			return -EINVAL;
+		}
+
+		ret = regmap_update_bits(tcsr, TCSR_ESS_INTERFACE_SEL_REG,
+					 TCSR_ESS_INTERFACE_SEL_MASK, val);
+		if (ret)
+			return ret;
+	}
+
+	if (of_find_property(node, "qcom,wifi-glb-cfg-enable-axid", NULL) &&
+	    of_device_is_compatible(node, "qcom,tcsr-ipq4019")) {
+		ret = regmap_set_bits(tcsr, TCSR_WIFI0_GLB_CFG_OFFSET_REG,
+				      TCSR_WIFI_GLB_CFG_AXID_EN);
+		ret = regmap_set_bits(tcsr, TCSR_WIFI1_GLB_CFG_OFFSET_REG,
+				      TCSR_WIFI_GLB_CFG_AXID_EN);
+		if (ret)
+			return ret;
+	}
+
+	if (of_find_property(node, "qcom,wifi-glb-cfg-socslv-mode", NULL) &&
+	    of_device_is_compatible(node, "qcom,tcsr-ipq4019")) {
+		if (of_property_match_string(node, "qcom,wifi-glb-cfg-socslv-mode",
+					     "snoc")) {
+			val = TCSR_WIFI_GLB_CFG_SOCSLV_SNOC;
+		} else if (of_property_match_string(node, "qcom,wifi-glb-cfg-socslv-mode",
+						  "local")) {
+			val = TCSR_WIFI_GLB_CFG_SOCSLV_SNOC;
+		} else {
+			dev_err(dev, "invalid value for qcom,wifi-glb-cfg-socslv-mode");
+			return -EINVAL;
+		}
+
+		ret = regmap_update_bits(tcsr, TCSR_WIFI0_GLB_CFG_OFFSET_REG,
+					 TCSR_WIFI_GLB_CFG_SOCSLV_WXI_BVALID, val);
+		ret = regmap_update_bits(tcsr, TCSR_WIFI1_GLB_CFG_OFFSET_REG,
+					 TCSR_WIFI_GLB_CFG_SOCSLV_WXI_BVALID, val);
+	}
+
+	if (of_find_property(node, "qcom,wifi_noc_memtype_m0_m2", NULL) &&
+	    of_device_is_compatible(node, "qcom,tcsr-ipq4019")) {
+		ret = regmap_update_bits(tcsr, TCSR_PNOC_SNOC_MEMTYPE_M0_M2_REG,
+					 TCSR_WIFI_NOC_MEMTYPE_MASK,
+					 TCSR_WIFI_NOC_MEMTYPE_M0_M2);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id qcom_tcsr_dt_match[] = {
+	{ .compatible = "qcom,tcsr-ipq8064", },
+	{ .compatible = "qcom,tcsr-ipq4019", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, qcom_tcsr_dt_match);
+
+static struct platform_driver qcom_tcsr_driver = {
+	.probe = qcom_tcsr_probe,
+	.driver = {
+		.name		= "qcom-tcsr",
+		.of_match_table	= qcom_tcsr_dt_match,
+	},
+};
+
+module_platform_driver(qcom_tcsr_driver);
+
+MODULE_AUTHOR("Ansuel Smith <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("QCOM TCSR driver");
+MODULE_LICENSE("GPL v2");
-- 
2.33.1


      parent reply	other threads:[~2022-01-22  0:16 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-22  0:16 [PATCH 0/2] Add QCOM TCSR driver Ansuel Smith
2022-01-22  0:16 ` [PATCH 1/2] dt-bindings: soc: qcom: add qcom,tcsr bindings Ansuel Smith
2022-01-31 23:41   ` Bjorn Andersson
2022-02-01 21:49     ` Ansuel Smith
2022-02-09 23:17       ` Bjorn Andersson
2022-02-09  3:01   ` Rob Herring
2022-01-22  0:16 ` Ansuel Smith [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220122001609.15904-3-ansuelsmth@gmail.com \
    --to=ansuelsmth@gmail.com \
    --cc=agross@kernel.org \
    --cc=bjorn.andersson@linaro.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).