]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
pinctrl: zynqmp: Add pinctrl driver
authorAshok Reddy Soma <ashok.reddy.soma@xilinx.com>
Wed, 23 Feb 2022 14:23:05 +0000 (15:23 +0100)
committerMichal Simek <michal.simek@amd.com>
Mon, 14 Mar 2022 14:23:31 +0000 (15:23 +0100)
Add pinctrl driver for Xilinx ZynqMP SOC. This driver is compatible with
linux device tree parameters for configuring pinmux and pinconf.

Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Link: https://lore.kernel.org/r/2d7eefa83c8c0129f7243a25de56a289e948f6c6.1645626183.git.michal.simek@xilinx.com
MAINTAINERS
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-zynqmp.c [new file with mode: 0644]
include/zynqmp_firmware.h

index 4e740fb5d262f61629deb4e606a4ca111ca47fdf..915316a86e95e2df67034ced848e68fb4f0d76da 100644 (file)
@@ -620,6 +620,7 @@ F:  drivers/mtd/nand/raw/zynq_nand.c
 F:     drivers/net/phy/ethernet_id.c
 F:     drivers/net/phy/xilinx_phy.c
 F:     drivers/net/zynq_gem.c
+F:     drivers/pinctrl/pinctrl-zynqmp.c
 F:     drivers/serial/serial_zynq.c
 F:     drivers/spi/zynq_qspi.c
 F:     drivers/spi/zynq_spi.c
index 03946245c7d5d6566a3ed54783fd3ba26202beb1..d7477d7c336412ff9c902bc42d324c4fdf23c314 100644 (file)
@@ -318,6 +318,16 @@ config PINCTRL_K210
          Support pin multiplexing on the K210. The "FPIOA" can remap any
          supported function to any multifunctional IO pin. It can also perform
          basic GPIO functions, such as reading the current value of a pin.
+
+config PINCTRL_ZYNQMP
+       bool "Xilinx ZynqMP pin control driver"
+       depends on DM && PINCTRL_GENERIC && ARCH_ZYNQMP
+       default y
+       help
+         Support pin multiplexing control on Xilinx ZynqMP. The driver uses
+         Generic Pinctrl framework and is compatible with the Linux driver,
+         i.e. it uses the same device tree configuration.
+
 endif
 
 source "drivers/pinctrl/broadcom/Kconfig"
index fd736a7f640a95b1c47a27dded6c95b24b17702c..ddddd13433c5343fc60aebf77a6654460c59de48 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_PINCTRL_STI)     += pinctrl-sti.o
 obj-$(CONFIG_PINCTRL_STM32)    += pinctrl_stm32.o
 obj-$(CONFIG_$(SPL_)PINCTRL_STMFX)     += pinctrl-stmfx.o
 obj-y                          += broadcom/
+obj-$(CONFIG_PINCTRL_ZYNQMP)   += pinctrl-zynqmp.o
diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
new file mode 100644 (file)
index 0000000..7c5a02d
--- /dev/null
@@ -0,0 +1,644 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx pinctrl driver for ZynqMP
+ *
+ * Author(s):   Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
+ *              Michal Simek <michal.simek@xilinx.com>
+ *
+ * Copyright (C) 2021 Xilinx, Inc. All rights reserved.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <zynqmp_firmware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/pinctrl.h>
+#include <linux/compat.h>
+#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
+
+#define PINCTRL_GET_FUNC_GROUPS_RESP_LEN       12
+#define PINCTRL_GET_PIN_GROUPS_RESP_LEN                12
+#define NUM_GROUPS_PER_RESP                    6
+#define NA_GROUP                               -1
+#define RESERVED_GROUP                         -2
+#define MAX_GROUP_PIN                          50
+#define MAX_PIN_GROUPS                         50
+#define MAX_GROUP_NAME_LEN                     32
+#define MAX_FUNC_NAME_LEN                      16
+
+#define DRIVE_STRENGTH_2MA     2
+#define DRIVE_STRENGTH_4MA     4
+#define DRIVE_STRENGTH_8MA     8
+#define DRIVE_STRENGTH_12MA    12
+
+/*
+ * This driver works with very simple configuration that has the same name
+ * for group and function. This way it is compatible with the Linux Kernel
+ * driver.
+ */
+struct zynqmp_pinctrl_priv {
+       u32 npins;
+       u32 nfuncs;
+       u32 ngroups;
+       struct zynqmp_pmux_function *funcs;
+       struct zynqmp_pctrl_group *groups;
+};
+
+/**
+ * struct zynqmp_pinctrl_config - pinconfig parameters
+ * @slew:              Slew rate slow or fast
+ * @bias:              Bias enabled or disabled
+ * @pull_ctrl:         Pull control pull up or pull down
+ * @input_type:                CMOS or Schmitt
+ * @drive_strength:    Drive strength 2mA/4mA/8mA/12mA
+ * @volt_sts:          Voltage status 1.8V or 3.3V
+ * @tri_state:         Tristate enabled or disabled
+ *
+ * This structure holds information about pin control config
+ * option that can be set for each pin.
+ */
+struct zynqmp_pinctrl_config {
+       u32 slew;
+       u32 bias;
+       u32 pull_ctrl;
+       u32 input_type;
+       u32 drive_strength;
+       u32 volt_sts;
+       u32 tri_state;
+};
+
+/**
+ * enum zynqmp_pin_config_param - possible pin configuration parameters
+ * @PIN_CONFIG_IOSTANDARD:     if the pin can select an IO standard,
+ *                             the argument to this parameter (on a
+ *                             custom format) tells the driver which
+ *                             alternative IO standard to use
+ * @PIN_CONFIG_SCHMITTCMOS:    this parameter (on a custom format) allows
+ *                             to select schmitt or cmos input for MIO pins
+ */
+enum zynqmp_pin_config_param {
+       PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1,
+       PIN_CONFIG_SCHMITTCMOS,
+};
+
+/**
+ * struct zynqmp_pmux_function - a pinmux function
+ * @name:      Name of the pinmux function
+ * @groups:    List of pingroups for this function
+ * @ngroups:   Number of entries in @groups
+ *
+ * This structure holds information about pin control function
+ * and function group names supporting that function.
+ */
+struct zynqmp_pmux_function {
+       char name[MAX_FUNC_NAME_LEN];
+       const char * const *groups;
+       unsigned int ngroups;
+};
+
+/**
+ * struct zynqmp_pctrl_group - Pin control group info
+ * @name:      Group name
+ * @pins:      Group pin numbers
+ * @npins:     Number of pins in group
+ */
+struct zynqmp_pctrl_group {
+       const char *name;
+       unsigned int pins[MAX_GROUP_PIN];
+       unsigned int npins;
+};
+
+static char pin_name[PINNAME_SIZE];
+
+/**
+ * zynqmp_pm_query_data() - Get query data from firmware
+ * @qid:       Value of enum pm_query_id
+ * @arg1:      Argument 1
+ * @arg2:      Argument 2
+ * @out:       Returned output value
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_query_data(enum pm_query_id qid, u32 arg1, u32 arg2, u32 *out)
+{
+       int ret;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       ret = xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, ret_payload);
+       if (ret)
+               return ret;
+
+       *out = ret_payload[1];
+
+       return ret;
+}
+
+static int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param, u32 *value)
+{
+       int ret;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       /* Get config for the pin */
+       ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, 0, 0, ret_payload);
+       if (ret) {
+               printf("%s failed\n", __func__);
+               return ret;
+       }
+
+       *value = ret_payload[1];
+
+       return ret;
+}
+
+static int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, u32 value)
+{
+       int ret;
+
+       /* Request the pin first */
+       ret = xilinx_pm_request(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL);
+       if (ret) {
+               printf("%s: pin request failed\n", __func__);
+               return ret;
+       }
+
+       /* Set config for the pin */
+       ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, pin, param, value, 0, NULL);
+       if (ret) {
+               printf("%s failed\n", __func__);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int zynqmp_pinctrl_get_function_groups(u32 fid, u32 index, u16 *groups)
+{
+       int ret;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_GROUPS,
+                               fid, index, 0, ret_payload);
+       if (ret) {
+               printf("%s failed\n", __func__);
+               return ret;
+       }
+
+       memcpy(groups, &ret_payload[1], PINCTRL_GET_FUNC_GROUPS_RESP_LEN);
+
+       return ret;
+}
+
+static int zynqmp_pinctrl_prepare_func_groups(u32 fid,
+                                             struct zynqmp_pmux_function *func,
+                                             struct zynqmp_pctrl_group *groups)
+{
+       const char **fgroups;
+       char name[MAX_GROUP_NAME_LEN];
+       u16 resp[NUM_GROUPS_PER_RESP] = {0};
+       int ret, index, i;
+
+       fgroups = kcalloc(func->ngroups, sizeof(*fgroups), GFP_KERNEL);
+       if (!fgroups)
+               return -ENOMEM;
+
+       for (index = 0; index < func->ngroups; index += NUM_GROUPS_PER_RESP) {
+               ret = zynqmp_pinctrl_get_function_groups(fid, index, resp);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+                       if (resp[i] == (u16)NA_GROUP)
+                               goto done;
+                       if (resp[i] == (u16)RESERVED_GROUP)
+                               continue;
+
+                       snprintf(name, MAX_GROUP_NAME_LEN, "%s_%d_grp",
+                                func->name, index + i);
+                       fgroups[index + i] = strdup(name);
+
+                       snprintf(name, MAX_GROUP_NAME_LEN, "%s_%d_grp",
+                                func->name, index + i);
+                       groups[resp[i]].name = strdup(name);
+               }
+       }
+done:
+       func->groups = fgroups;
+
+       return ret;
+}
+
+static int zynqmp_pinctrl_get_pin_groups(u32 pin, u32 index, u16 *groups)
+{
+       int ret;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_PIN_GROUPS,
+                               pin, index, 0, ret_payload);
+       if (ret) {
+               printf("%s failed to get pin groups\n", __func__);
+               return ret;
+       }
+
+       memcpy(groups, &ret_payload[1], PINCTRL_GET_PIN_GROUPS_RESP_LEN);
+
+       return ret;
+}
+
+static void zynqmp_pinctrl_group_add_pin(struct zynqmp_pctrl_group *group,
+                                        unsigned int pin)
+{
+       group->pins[group->npins++] = pin;
+}
+
+static int zynqmp_pinctrl_create_pin_groups(struct zynqmp_pctrl_group *groups,
+                                           unsigned int pin)
+{
+       u16 resp[NUM_GROUPS_PER_RESP] = {0};
+       int ret, i, index = 0;
+
+       do {
+               ret = zynqmp_pinctrl_get_pin_groups(pin, index, resp);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+                       if (resp[i] == (u16)NA_GROUP)
+                               goto done;
+                       if (resp[i] == (u16)RESERVED_GROUP)
+                               continue;
+                       zynqmp_pinctrl_group_add_pin(&groups[resp[i]], pin);
+               }
+               index += NUM_GROUPS_PER_RESP;
+       } while (index <= MAX_PIN_GROUPS);
+
+done:
+       return ret;
+}
+
+static int zynqmp_pinctrl_probe(struct udevice *dev)
+{
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+       int ret, i;
+       u32 pin;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       /* Get number of pins first */
+       ret = zynqmp_pm_query_data(PM_QID_PINCTRL_GET_NUM_PINS, 0, 0, &priv->npins);
+       if (ret) {
+               printf("%s failed to get no of pins\n", __func__);
+               return ret;
+       }
+
+       /* Get number of functions available */
+       ret = zynqmp_pm_query_data(PM_QID_PINCTRL_GET_NUM_FUNCTIONS, 0, 0, &priv->nfuncs);
+       if (ret) {
+               printf("%s failed to get no of functions\n", __func__);
+               return ret;
+       }
+
+       /* Allocating structures for functions and its groups */
+       priv->funcs = kzalloc(sizeof(*priv->funcs) * priv->nfuncs, GFP_KERNEL);
+       if (!priv->funcs)
+               return -ENOMEM;
+
+       for (i = 0; i < priv->nfuncs; i++) {
+               /* Get function name for the function and fill */
+               xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_NAME,
+                                 i, 0, 0, ret_payload);
+
+               memcpy((void *)priv->funcs[i].name, ret_payload, MAX_FUNC_NAME_LEN);
+
+               /* And fill number of groups available for certain function */
+               xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
+                                 i, 0, 0, ret_payload);
+
+               priv->funcs[i].ngroups = ret_payload[1];
+               priv->ngroups += priv->funcs[i].ngroups;
+       }
+
+       /* Prepare all groups */
+       priv->groups = kzalloc(sizeof(*priv->groups) * priv->ngroups,
+                              GFP_KERNEL);
+       if (!priv->groups)
+               return -ENOMEM;
+
+       for (i = 0; i < priv->nfuncs; i++) {
+               ret = zynqmp_pinctrl_prepare_func_groups(i, &priv->funcs[i],
+                                                        priv->groups);
+               if (ret) {
+                       printf("Failed to prepare_func_groups\n");
+                       return ret;
+               }
+       }
+
+       for (pin = 0; pin < priv->npins; pin++) {
+               ret = zynqmp_pinctrl_create_pin_groups(priv->groups, pin);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int zynqmp_pinctrl_get_functions_count(struct udevice *dev)
+{
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->nfuncs;
+}
+
+static const char *zynqmp_pinctrl_get_function_name(struct udevice *dev,
+                                                   unsigned int selector)
+{
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->funcs[selector].name;
+}
+
+static int zynqmp_pinmux_set(struct udevice *dev, unsigned int selector,
+                            unsigned int func_selector)
+{
+       int ret;
+
+       /* Request the pin first */
+       ret = xilinx_pm_request(PM_PINCTRL_REQUEST, selector, 0, 0, 0, NULL);
+       if (ret) {
+               printf("%s: pin request failed\n", __func__);
+               return ret;
+       }
+
+       /* Set the pin function */
+       ret = xilinx_pm_request(PM_PINCTRL_SET_FUNCTION, selector, func_selector,
+                               0, 0, NULL);
+       if (ret) {
+               printf("%s: Failed to set pinmux function\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int zynqmp_pinmux_group_set(struct udevice *dev, unsigned int selector,
+                                  unsigned int func_selector)
+{
+       int i;
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct zynqmp_pctrl_group *pgrp = &priv->groups[selector];
+
+       for (i = 0; i < pgrp->npins; i++)
+               zynqmp_pinmux_set(dev, pgrp->pins[i], func_selector);
+
+       return 0;
+}
+
+static int zynqmp_pinconf_set(struct udevice *dev, unsigned int pin,
+                             unsigned int param, unsigned int arg)
+{
+       int ret = 0;
+       unsigned int value;
+
+       switch (param) {
+       case PIN_CONFIG_SLEW_RATE:
+               param = PM_PINCTRL_CONFIG_SLEW_RATE;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+               param = PM_PINCTRL_CONFIG_PULL_CTRL;
+               arg = PM_PINCTRL_BIAS_PULL_UP;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               param = PM_PINCTRL_CONFIG_PULL_CTRL;
+               arg = PM_PINCTRL_BIAS_PULL_DOWN;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+               break;
+       case PIN_CONFIG_BIAS_DISABLE:
+               param = PM_PINCTRL_CONFIG_BIAS_STATUS;
+               arg = PM_PINCTRL_BIAS_DISABLE;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+               break;
+       case PIN_CONFIG_SCHMITTCMOS:
+               param = PM_PINCTRL_CONFIG_SCHMITT_CMOS;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               param = PM_PINCTRL_CONFIG_SCHMITT_CMOS;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+               break;
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               switch (arg) {
+               case DRIVE_STRENGTH_2MA:
+                       value = PM_PINCTRL_DRIVE_STRENGTH_2MA;
+                       break;
+               case DRIVE_STRENGTH_4MA:
+                       value = PM_PINCTRL_DRIVE_STRENGTH_4MA;
+                       break;
+               case DRIVE_STRENGTH_8MA:
+                       value = PM_PINCTRL_DRIVE_STRENGTH_8MA;
+                       break;
+               case DRIVE_STRENGTH_12MA:
+                       value = PM_PINCTRL_DRIVE_STRENGTH_12MA;
+                       break;
+               default:
+                       /* Invalid drive strength */
+                       dev_warn(dev, "Invalid drive strength for pin %d\n", pin);
+                       return -EINVAL;
+               }
+
+               param = PM_PINCTRL_CONFIG_DRIVE_STRENGTH;
+               ret = zynqmp_pm_pinctrl_set_config(pin, param, value);
+               break;
+       case PIN_CONFIG_IOSTANDARD:
+               param = PM_PINCTRL_CONFIG_VOLTAGE_STATUS;
+               ret = zynqmp_pm_pinctrl_get_config(pin, param, &value);
+               if (arg != value)
+                       dev_warn(dev, "Invalid IO Standard requested for pin %d\n",
+                                pin);
+               break;
+       case PIN_CONFIG_POWER_SOURCE:
+               param = PM_PINCTRL_CONFIG_VOLTAGE_STATUS;
+               ret = zynqmp_pm_pinctrl_get_config(pin, param, &value);
+               if (arg != value)
+                       dev_warn(dev, "Invalid IO Standard requested for pin %d\n",
+                                pin);
+               break;
+       case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+       case PIN_CONFIG_LOW_POWER_MODE:
+               /*
+                * This cases are mentioned in dts but configurable
+                * registers are unknown. So falling through to ignore
+                * boot time warnings as of now.
+                */
+               ret = 0;
+               break;
+       default:
+               dev_warn(dev, "unsupported configuration parameter '%u'\n",
+                        param);
+               ret = -ENOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+
+static int zynqmp_pinconf_group_set(struct udevice *dev,
+                                   unsigned int group_selector,
+                                   unsigned int param, unsigned int arg)
+{
+       int i;
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct zynqmp_pctrl_group *pgrp = &priv->groups[group_selector];
+
+       for (i = 0; i < pgrp->npins; i++)
+               zynqmp_pinconf_set(dev, pgrp->pins[i], param, arg);
+
+       return 0;
+}
+
+static int zynqmp_pinctrl_get_pins_count(struct udevice *dev)
+{
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->npins;
+}
+
+static const char *zynqmp_pinctrl_get_pin_name(struct udevice *dev,
+                                              unsigned int selector)
+{
+       snprintf(pin_name, PINNAME_SIZE, "MIO%d", selector);
+
+       return pin_name;
+}
+
+static int zynqmp_pinctrl_get_pin_muxing(struct udevice *dev,
+                                        unsigned int selector,
+                                        char *buf,
+                                        int size)
+{
+       struct zynqmp_pinctrl_config pinmux;
+
+       zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_SLEW_RATE,
+                                    &pinmux.slew);
+       zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_BIAS_STATUS,
+                                    &pinmux.bias);
+       zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_PULL_CTRL,
+                                    &pinmux.pull_ctrl);
+       zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_SCHMITT_CMOS,
+                                    &pinmux.input_type);
+       zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_DRIVE_STRENGTH,
+                                    &pinmux.drive_strength);
+       zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_VOLTAGE_STATUS,
+                                    &pinmux.volt_sts);
+
+       switch (pinmux.drive_strength) {
+       case PM_PINCTRL_DRIVE_STRENGTH_2MA:
+               pinmux.drive_strength = DRIVE_STRENGTH_2MA;
+               break;
+       case PM_PINCTRL_DRIVE_STRENGTH_4MA:
+               pinmux.drive_strength = DRIVE_STRENGTH_4MA;
+               break;
+       case PM_PINCTRL_DRIVE_STRENGTH_8MA:
+               pinmux.drive_strength = DRIVE_STRENGTH_8MA;
+               break;
+       case PM_PINCTRL_DRIVE_STRENGTH_12MA:
+               pinmux.drive_strength = DRIVE_STRENGTH_12MA;
+               break;
+       default:
+               /* Invalid drive strength */
+               dev_warn(dev, "Invalid drive strength\n");
+               return -EINVAL;
+       }
+
+       snprintf(buf, size, "slew:%s\tbias:%s\tpull:%s\tinput:%s\tdrive:%dmA\tvolt:%s",
+                pinmux.slew ? "slow" : "fast",
+                pinmux.bias ? "enabled" : "disabled",
+                pinmux.pull_ctrl ? "up" : "down",
+                pinmux.input_type ? "schmitt" : "cmos",
+                pinmux.drive_strength,
+                pinmux.volt_sts ? "1.8" : "3.3");
+
+       return 0;
+}
+
+static int zynqmp_pinctrl_get_groups_count(struct udevice *dev)
+{
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->ngroups;
+}
+
+static const char *zynqmp_pinctrl_get_group_name(struct udevice *dev,
+                                                unsigned int selector)
+{
+       struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->groups[selector].name;
+}
+
+static const struct pinconf_param zynqmp_conf_params[] = {
+       { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+       { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+       { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+       { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+       { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+       { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+       { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+       { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+       { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
+       { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+       { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
+       { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
+       { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+       { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+       { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
+       { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+       { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+       { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
+       { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
+       { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
+       { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+       { "output-high", PIN_CONFIG_OUTPUT, 1, },
+       { "output-low", PIN_CONFIG_OUTPUT, 0, },
+       { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
+       { "sleep-hardware-state", PIN_CONFIG_SLEEP_HARDWARE_STATE, 0 },
+       { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
+       { "skew-delay", PIN_CONFIG_SKEW_DELAY, 0 },
+       /* zynqmp specific */
+       {"io-standard", PIN_CONFIG_IOSTANDARD, IO_STANDARD_LVCMOS18},
+       {"schmitt-cmos", PIN_CONFIG_SCHMITTCMOS, PM_PINCTRL_INPUT_TYPE_SCHMITT},
+};
+
+static struct pinctrl_ops zynqmp_pinctrl_ops = {
+       .get_pins_count = zynqmp_pinctrl_get_pins_count,
+       .get_pin_name = zynqmp_pinctrl_get_pin_name,
+       .get_pin_muxing = zynqmp_pinctrl_get_pin_muxing,
+       .set_state = pinctrl_generic_set_state,
+       .get_groups_count = zynqmp_pinctrl_get_groups_count,
+       .get_group_name = zynqmp_pinctrl_get_group_name,
+       .get_functions_count = zynqmp_pinctrl_get_functions_count,
+       .get_function_name = zynqmp_pinctrl_get_function_name,
+       .pinmux_group_set = zynqmp_pinmux_group_set,
+       .pinmux_set = zynqmp_pinmux_set,
+       .pinconf_params = zynqmp_conf_params,
+       .pinconf_group_set = zynqmp_pinconf_group_set,
+       .pinconf_set = zynqmp_pinconf_set,
+       .pinconf_num_params = ARRAY_SIZE(zynqmp_conf_params),
+};
+
+static const struct udevice_id zynqmp_pinctrl_ids[] = {
+       { .compatible = "xlnx,zynqmp-pinctrl" },
+       { }
+};
+
+U_BOOT_DRIVER(pinctrl_zynqmp) = {
+       .name = "zynqmp-pinctrl",
+       .id = UCLASS_PINCTRL,
+       .of_match = zynqmp_pinctrl_ids,
+       .priv_auto = sizeof(struct zynqmp_pinctrl_priv),
+       .ops = &zynqmp_pinctrl_ops,
+       .probe = zynqmp_pinctrl_probe,
+};
index 60c3df3da41a5f87561149870f4beef0c1e81cf7..f577008736d9ac0f421ec534cee527e1388152b7 100644 (file)
@@ -177,6 +177,49 @@ enum pm_query_id {
        PM_QID_CLOCK_GET_MAX_DIVISOR = 13,
 };
 
+enum pm_pinctrl_config_param {
+       PM_PINCTRL_CONFIG_SLEW_RATE = 0,
+       PM_PINCTRL_CONFIG_BIAS_STATUS = 1,
+       PM_PINCTRL_CONFIG_PULL_CTRL = 2,
+       PM_PINCTRL_CONFIG_SCHMITT_CMOS = 3,
+       PM_PINCTRL_CONFIG_DRIVE_STRENGTH = 4,
+       PM_PINCTRL_CONFIG_VOLTAGE_STATUS = 5,
+       PM_PINCTRL_CONFIG_TRI_STATE = 6,
+       PM_PINCTRL_CONFIG_MAX = 7,
+};
+
+enum pm_pinctrl_slew_rate {
+       PM_PINCTRL_SLEW_RATE_FAST = 0,
+       PM_PINCTRL_SLEW_RATE_SLOW = 1,
+};
+
+enum pm_pinctrl_bias_status {
+       PM_PINCTRL_BIAS_DISABLE = 0,
+       PM_PINCTRL_BIAS_ENABLE = 1,
+};
+
+enum pm_pinctrl_pull_ctrl {
+       PM_PINCTRL_BIAS_PULL_DOWN = 0,
+       PM_PINCTRL_BIAS_PULL_UP = 1,
+};
+
+enum pm_pinctrl_schmitt_cmos {
+       PM_PINCTRL_INPUT_TYPE_CMOS = 0,
+       PM_PINCTRL_INPUT_TYPE_SCHMITT = 1,
+};
+
+enum pm_pinctrl_drive_strength {
+       PM_PINCTRL_DRIVE_STRENGTH_2MA = 0,
+       PM_PINCTRL_DRIVE_STRENGTH_4MA = 1,
+       PM_PINCTRL_DRIVE_STRENGTH_8MA = 2,
+       PM_PINCTRL_DRIVE_STRENGTH_12MA = 3,
+};
+
+enum pm_pinctrl_tri_state {
+       PM_PINCTRL_TRI_STATE_DISABLE = 0,
+       PM_PINCTRL_TRI_STATE_ENABLE = 1,
+};
+
 enum zynqmp_pm_reset_action {
        PM_RESET_ACTION_RELEASE = 0,
        PM_RESET_ACTION_ASSERT = 1,