All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Simek <monstr@monstr.eu>
To: U-Boot <u-boot@lists.denx.de>, git <git@xilinx.com>
Cc: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>,
	Dylan Hung <dylan_hung@aspeedtech.com>,
	 Mark Kettenis <kettenis@openbsd.org>,
	Ryan Chen <ryan_chen@aspeedtech.com>,
	 Yuan Fang <fangyuanseu@gmail.com>
Subject: Re: [PATCH 2/2] pinctrl: zynqmp: Add pinctrl driver
Date: Mon, 7 Mar 2022 08:58:23 +0100	[thread overview]
Message-ID: <CAHTX3dJ7vb9bNs9Ez+U+N3MWfwNEOr0GS-8Ufp4RyKBVHh5QNw@mail.gmail.com> (raw)
In-Reply-To: <2d7eefa83c8c0129f7243a25de56a289e948f6c6.1645626183.git.michal.simek@xilinx.com>

st 23. 2. 2022 v 15:23 odesílatel Michal Simek <michal.simek@xilinx.com> napsal:
>
> From: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
>
> 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>
> ---
>
>  MAINTAINERS                      |   1 +
>  drivers/pinctrl/Kconfig          |  10 +
>  drivers/pinctrl/Makefile         |   1 +
>  drivers/pinctrl/pinctrl-zynqmp.c | 644 +++++++++++++++++++++++++++++++
>  include/zynqmp_firmware.h        |  43 +++
>  5 files changed, 699 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-zynqmp.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index fb171e0c687b..c1a5ac95f295 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -619,6 +619,7 @@ F:  drivers/mmc/zynq_sdhci.c
>  F:     drivers/mtd/nand/raw/zynq_nand.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
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 03946245c7d5..d7477d7c3364 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -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"
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index fd736a7f640a..ddddd13433c5 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -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
> index 000000000000..7c5a02db1b98
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-zynqmp.c
> @@ -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,
> +};
> diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h
> index 50bf4ef39535..41abc2eee951 100644
> --- a/include/zynqmp_firmware.h
> +++ b/include/zynqmp_firmware.h
> @@ -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,
> --
> 2.35.1
>

Applied.
M

-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs

  reply	other threads:[~2022-03-07  7:58 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-23 14:23 [PATCH 1/2] pinctrl: Increase length of pinmux status buffer Michal Simek
2022-02-23 14:23 ` [PATCH 2/2] pinctrl: zynqmp: Add pinctrl driver Michal Simek
2022-03-07  7:58   ` Michal Simek [this message]
2022-03-07  7:57 ` [PATCH 1/2] pinctrl: Increase length of pinmux status buffer Michal Simek

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=CAHTX3dJ7vb9bNs9Ez+U+N3MWfwNEOr0GS-8Ufp4RyKBVHh5QNw@mail.gmail.com \
    --to=monstr@monstr.eu \
    --cc=ashok.reddy.soma@xilinx.com \
    --cc=dylan_hung@aspeedtech.com \
    --cc=fangyuanseu@gmail.com \
    --cc=git@xilinx.com \
    --cc=kettenis@openbsd.org \
    --cc=ryan_chen@aspeedtech.com \
    --cc=u-boot@lists.denx.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.