#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
 
+#include <linux/bitfield.h>
 #include <linux/bitmap.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #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
 };
 
 static struct pinctrl_desc zynqmp_desc;
+static u32 family_code;
+static u32 sub_family_code;
 
 static int zynqmp_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
 {
                        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 (family_code == ZYNQMP_FAMILY_CODE)
+                                       __set_bit(groups[resp[i]].pins[pin], used_pins);
+                               else
+                                       __set_bit((u8)groups[resp[i]].pins[pin] - 1, used_pins);
+                       }
                }
        }
 done:
        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;
        if (!pctrl)
                return -ENOMEM;
 
-       ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev,
-                                             &zynqmp_desc.pins,
-                                             &zynqmp_desc.npins);
+       ret = zynqmp_pm_get_family_info(&family_code, &sub_family_code);
+       if (ret < 0)
+               return ret;
+
+       if (family_code == ZYNQMP_FAMILY_CODE) {
+               ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins,
+                                                     &zynqmp_desc.npins);
+       } else {
+               ret = versal_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;
 
 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);