diff mbox series

[3/3] pinctrl: pinctrl-zynqmp: Add support for Versal platform

Message ID 20240711103317.891813-4-sai.krishna.potthuri@amd.com
State Superseded
Headers show
Series pinctrl: pinctrl-zynqmp: Add Versal platform support | expand

Commit Message

Sai Krishna Potthuri July 11, 2024, 10:33 a.m. UTC
Add Pinctrl support for Xilinx Versal platform.
Driver checks for firmware support to retrieve the Pin information, if it
is supported then proceed further otherwise it returns error saying
operation not supported. Latest Xilinx Platform Management Firmware must
be used to make use of the Pinctrl driver for Versal platform.

Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
---
 drivers/pinctrl/pinctrl-zynqmp.c | 91 ++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 5 deletions(-)

Comments

Buddhabhatti, Jay July 11, 2024, 11:19 a.m. UTC | #1
Hi Sai,

>-----Original Message-----
>From: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
>Sent: Thursday, July 11, 2024 4:03 PM
>To: Linus Walleij <linus.walleij@linaro.org>; Simek, Michal
><michal.simek@amd.com>; Rob Herring <robh+dt@kernel.org>; Krzysztof
>Kozlowski <krzysztof.kozlowski+dt@linaro.org>; Conor Dooley
><conor+dt@kernel.org>; Buddhabhatti, Jay <jay.buddhabhatti@amd.com>;
>Dhaval Shah <dhaval.r.shah@amd.com>; Kundanala, Praveen Teja
><praveen.teja.kundanala@amd.com>; Greg Kroah-Hartman
><gregkh@linuxfoundation.org>
>Cc: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux-
>gpio@vger.kernel.org; devicetree@vger.kernel.org; saikrishna12468@gmail.com;
>git (AMD-Xilinx) <git@amd.com>; Potthuri, Sai Krishna
><sai.krishna.potthuri@amd.com>
>Subject: [PATCH 3/3] pinctrl: pinctrl-zynqmp: Add support for Versal platform
>
>Add Pinctrl support for Xilinx Versal platform.
>Driver checks for firmware support to retrieve the Pin information, if it
>is supported then proceed further otherwise it returns error saying
>operation not supported. Latest Xilinx Platform Management Firmware must
>be used to make use of the Pinctrl driver for Versal platform.
>
>Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
>---
> drivers/pinctrl/pinctrl-zynqmp.c | 91 ++++++++++++++++++++++++++++++--
> 1 file changed, 86 insertions(+), 5 deletions(-)
>
>diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
>index 3c6d56fdb8c9..e2cfd3d512e8 100644
>--- a/drivers/pinctrl/pinctrl-zynqmp.c
>+++ b/drivers/pinctrl/pinctrl-zynqmp.c
>@@ -10,6 +10,7 @@
>
> #include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
>
>+#include <linux/bitfield.h>
> #include <linux/bitmap.h>
> #include <linux/init.h>
> #include <linux/module.h>
>@@ -44,6 +45,12 @@
> #define DRIVE_STRENGTH_8MA	8
> #define DRIVE_STRENGTH_12MA	12
>
>+#define VERSAL_LPD_PIN_PREFIX		"LPD_MIO"
>+#define VERSAL_PMC_PIN_PREFIX		"PMC_MIO"
>+
>+#define VERSAL_PINCTRL_ATTR_NODETYPE_MASK	GENMASK(19, 14)
>+#define VERSAL_PINCTRL_NODETYPE_LPD_MIO		BIT(0)
>+
> /**
>  * struct zynqmp_pmux_function - a pinmux function
>  * @name:	Name of the pin mux function
>@@ -596,8 +603,12 @@ static int zynqmp_pinctrl_prepare_func_groups(struct
>device *dev, u32 fid,
> 			if (!groups[resp[i]].name)
> 				return -ENOMEM;
>
>-			for (pin = 0; pin < groups[resp[i]].npins; pin++)
>-				__set_bit(groups[resp[i]].pins[pin], used_pins);
>+			for (pin = 0; pin < groups[resp[i]].npins; pin++) {
>+				if (of_device_is_compatible(dev->of_node,
>"xlnx,zynqmp-pinctrl"))

Use zynqmp_pm_get_family_info() to distinguish ZynqMP or Versal platform instead of depending on compatible string.
Refer drivers/firmware/xilinx/zynqmp.c for more info.

>+					__set_bit(groups[resp[i]].pins[pin],
>used_pins);
>+				else
>+					__set_bit((u8)groups[resp[i]].pins[pin] -
>1, used_pins);
>+			}
> 		}
> 	}
> done:
>@@ -873,6 +884,70 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct
>device *dev,
> 	return 0;
> }
>
>+static int versal_pinctrl_get_attributes(u32 pin_idx, u32 *response)
>+{
>+	struct zynqmp_pm_query_data qdata = {0};
>+	u32 payload[PAYLOAD_ARG_CNT];
>+	int ret;
>+
>+	qdata.qid = PM_QID_PINCTRL_GET_ATTRIBUTES;
>+	qdata.arg1 = pin_idx;
>+
>+	ret = zynqmp_pm_query_data(qdata, payload);
>+	if (ret)
>+		return ret;
>+
>+	memcpy(response, &payload[1], sizeof(*response));
>+
>+	return 0;
>+}
>+
>+static int versal_pinctrl_prepare_pin_desc(struct device *dev,
>+					   const struct pinctrl_pin_desc
>**zynqmp_pins,
>+					   unsigned int *npins)
>+{
>+	u32 lpd_mio_pins = 0, attr, nodetype;
>+	struct pinctrl_pin_desc *pins, *pin;
>+	int ret, i;
>+
>+	ret = zynqmp_pm_is_function_supported(PM_QUERY_DATA,
>PM_QID_PINCTRL_GET_ATTRIBUTES);
>+	if (ret)
>+		return ret;
>+
>+	ret = zynqmp_pinctrl_get_num_pins(npins);
>+	if (ret)
>+		return ret;
>+
>+	pins = devm_kzalloc(dev, sizeof(*pins) * *npins, GFP_KERNEL);
>+	if (!pins)
>+		return -ENOMEM;
>+
>+	for (i = 0; i < *npins; i++) {
>+		ret = versal_pinctrl_get_attributes(i, &attr);
>+		if (ret)
>+			return ret;
>+
>+		pin = &pins[i];
>+		pin->number = attr;
>+		nodetype =
>FIELD_GET(VERSAL_PINCTRL_ATTR_NODETYPE_MASK, attr);
>+		if (nodetype == VERSAL_PINCTRL_NODETYPE_LPD_MIO) {
>+			pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
>+						   VERSAL_LPD_PIN_PREFIX, i);
>+			lpd_mio_pins++;
>+		} else {
>+			pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
>+						   VERSAL_PMC_PIN_PREFIX, i -
>lpd_mio_pins);
>+		}
>+
>+		if (!pin->name)
>+			return -ENOMEM;
>+	}
>+
>+	*zynqmp_pins = pins;
>+
>+	return 0;
>+}
>+
> static int zynqmp_pinctrl_probe(struct platform_device *pdev)
> {
> 	struct zynqmp_pinctrl *pctrl;
>@@ -882,9 +957,14 @@ static int zynqmp_pinctrl_probe(struct platform_device
>*pdev)
> 	if (!pctrl)
> 		return -ENOMEM;
>
>-	ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev,
>-					      &zynqmp_desc.pins,
>-					      &zynqmp_desc.npins);
>+	if (of_device_is_compatible(pdev->dev.of_node, "xlnx,versal-pinctrl")) {

Same as above.

>+		ret = versal_pinctrl_prepare_pin_desc(&pdev->dev,
>&zynqmp_desc.pins,
>+						      &zynqmp_desc.npins);
>+	} else {
>+		ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev,
>&zynqmp_desc.pins,
>+						      &zynqmp_desc.npins);
>+	}
>+
> 	if (ret) {
> 		dev_err(&pdev->dev, "pin desc prepare fail with %d\n", ret);
> 		return ret;
>@@ -907,6 +987,7 @@ static int zynqmp_pinctrl_probe(struct platform_device
>*pdev)
>
> static const struct of_device_id zynqmp_pinctrl_of_match[] = {
> 	{ .compatible = "xlnx,zynqmp-pinctrl" },
>+	{ .compatible = "xlnx,versal-pinctrl" },
> 	{ }
> };
> MODULE_DEVICE_TABLE(of, zynqmp_pinctrl_of_match);
>--
>2.25.1
diff mbox series

Patch

diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
index 3c6d56fdb8c9..e2cfd3d512e8 100644
--- a/drivers/pinctrl/pinctrl-zynqmp.c
+++ b/drivers/pinctrl/pinctrl-zynqmp.c
@@ -10,6 +10,7 @@ 
 
 #include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
 
+#include <linux/bitfield.h>
 #include <linux/bitmap.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -44,6 +45,12 @@ 
 #define DRIVE_STRENGTH_8MA	8
 #define DRIVE_STRENGTH_12MA	12
 
+#define VERSAL_LPD_PIN_PREFIX		"LPD_MIO"
+#define VERSAL_PMC_PIN_PREFIX		"PMC_MIO"
+
+#define VERSAL_PINCTRL_ATTR_NODETYPE_MASK	GENMASK(19, 14)
+#define VERSAL_PINCTRL_NODETYPE_LPD_MIO		BIT(0)
+
 /**
  * struct zynqmp_pmux_function - a pinmux function
  * @name:	Name of the pin mux function
@@ -596,8 +603,12 @@  static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid,
 			if (!groups[resp[i]].name)
 				return -ENOMEM;
 
-			for (pin = 0; pin < groups[resp[i]].npins; pin++)
-				__set_bit(groups[resp[i]].pins[pin], used_pins);
+			for (pin = 0; pin < groups[resp[i]].npins; pin++) {
+				if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-pinctrl"))
+					__set_bit(groups[resp[i]].pins[pin], used_pins);
+				else
+					__set_bit((u8)groups[resp[i]].pins[pin] - 1, used_pins);
+			}
 		}
 	}
 done:
@@ -873,6 +884,70 @@  static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
 	return 0;
 }
 
+static int versal_pinctrl_get_attributes(u32 pin_idx, u32 *response)
+{
+	struct zynqmp_pm_query_data qdata = {0};
+	u32 payload[PAYLOAD_ARG_CNT];
+	int ret;
+
+	qdata.qid = PM_QID_PINCTRL_GET_ATTRIBUTES;
+	qdata.arg1 = pin_idx;
+
+	ret = zynqmp_pm_query_data(qdata, payload);
+	if (ret)
+		return ret;
+
+	memcpy(response, &payload[1], sizeof(*response));
+
+	return 0;
+}
+
+static int versal_pinctrl_prepare_pin_desc(struct device *dev,
+					   const struct pinctrl_pin_desc **zynqmp_pins,
+					   unsigned int *npins)
+{
+	u32 lpd_mio_pins = 0, attr, nodetype;
+	struct pinctrl_pin_desc *pins, *pin;
+	int ret, i;
+
+	ret = zynqmp_pm_is_function_supported(PM_QUERY_DATA, PM_QID_PINCTRL_GET_ATTRIBUTES);
+	if (ret)
+		return ret;
+
+	ret = zynqmp_pinctrl_get_num_pins(npins);
+	if (ret)
+		return ret;
+
+	pins = devm_kzalloc(dev, sizeof(*pins) * *npins, GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	for (i = 0; i < *npins; i++) {
+		ret = versal_pinctrl_get_attributes(i, &attr);
+		if (ret)
+			return ret;
+
+		pin = &pins[i];
+		pin->number = attr;
+		nodetype = FIELD_GET(VERSAL_PINCTRL_ATTR_NODETYPE_MASK, attr);
+		if (nodetype == VERSAL_PINCTRL_NODETYPE_LPD_MIO) {
+			pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+						   VERSAL_LPD_PIN_PREFIX, i);
+			lpd_mio_pins++;
+		} else {
+			pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+						   VERSAL_PMC_PIN_PREFIX, i - lpd_mio_pins);
+		}
+
+		if (!pin->name)
+			return -ENOMEM;
+	}
+
+	*zynqmp_pins = pins;
+
+	return 0;
+}
+
 static int zynqmp_pinctrl_probe(struct platform_device *pdev)
 {
 	struct zynqmp_pinctrl *pctrl;
@@ -882,9 +957,14 @@  static int zynqmp_pinctrl_probe(struct platform_device *pdev)
 	if (!pctrl)
 		return -ENOMEM;
 
-	ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev,
-					      &zynqmp_desc.pins,
-					      &zynqmp_desc.npins);
+	if (of_device_is_compatible(pdev->dev.of_node, "xlnx,versal-pinctrl")) {
+		ret = versal_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins,
+						      &zynqmp_desc.npins);
+	} else {
+		ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins,
+						      &zynqmp_desc.npins);
+	}
+
 	if (ret) {
 		dev_err(&pdev->dev, "pin desc prepare fail with %d\n", ret);
 		return ret;
@@ -907,6 +987,7 @@  static int zynqmp_pinctrl_probe(struct platform_device *pdev)
 
 static const struct of_device_id zynqmp_pinctrl_of_match[] = {
 	{ .compatible = "xlnx,zynqmp-pinctrl" },
+	{ .compatible = "xlnx,versal-pinctrl" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, zynqmp_pinctrl_of_match);