From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 58CBBC433F5 for ; Mon, 7 Mar 2022 07:58:45 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2FE2D83C3C; Mon, 7 Mar 2022 08:58:43 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=monstr.eu Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=monstr-eu.20210112.gappssmtp.com header.i=@monstr-eu.20210112.gappssmtp.com header.b="WFOY/7kT"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id CBCA383C36; Mon, 7 Mar 2022 08:58:40 +0100 (CET) Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 58D3083C4F for ; Mon, 7 Mar 2022 08:58:35 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=monstr.eu Authentication-Results: phobos.denx.de; spf=none smtp.mailfrom=monstr@monstr.eu Received: by mail-ed1-x536.google.com with SMTP id c20so215426edr.8 for ; Sun, 06 Mar 2022 23:58:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=monstr-eu.20210112.gappssmtp.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=pKdNmt5Z2/Dixx5zOsfhzacZbugUw9v7hNegQC8gcA4=; b=WFOY/7kTUHeRm1lw+dnG3CXV5v+d/k5XtPlUGQRWmtopiVnsmsLmJMIA+ZcU/sUhMn nPCgQrY/ajlLM6jwRK4PykWlYyfeMyfEzDSkA4aRU+HSNpRNxX6KNa43W7x1yauqStpM Zq+/sk6BTVQGF7mC4aOyQwbqCUyofUpR1h+mMaZtfSzdY/E/rE0vUI9kKl0VWDVur+EL Frx8mbgZ6AQnN8ZioiABoiYDJfgdI2Mg1TP4iPpnSqsaBeEZ3xMeYeNpqjEbVu6uvq/0 ZS3O9rChtLSh8piBnU7RM2AhKXCjZyyerZl9j5tSR1rIh2/hdGYEIm4vAq+RZnTebVcb ZBdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=pKdNmt5Z2/Dixx5zOsfhzacZbugUw9v7hNegQC8gcA4=; b=yoR/yNMytwFQ/4E3+tpiF9rng04zYQPGkqSSCqKRnFSWoX3XJPnepraDYlWNUBxGYG 4HIkU2t9vn8yYrc2PPVRI6W12bV3wH10F3GTfxXN1xGd73OjEW5qFZ7rs9obFEbgpJyR DjB1MXC3CSnh9ZwqWNYzpj/ljmLrvXouo0p5binfX6h7yzSSe1Hx7pQ2Glq0imSnU8qy G0kVrGEQ9OlpeUxMd618cDUDsmYCB+ISsZ4gNYbyatd6w9fyxb11fUlfKryJ54pae1iT bk74A4cbhF/eJNiu+ILiP2/oS1J4qX7W+FWMriZrt2TrpZgohnZNJXOnZG48XvNa3k0C JEAQ== X-Gm-Message-State: AOAM530Ah4iRmfhE6Ue+x6qkOghAOzsJWc6qrUL5rGUPPMH/B3sdGq4K NRi3Xyp5vBQE4A1v2F3+/YOBtQBsugRAlhjkB5cCCPNfB2o= X-Google-Smtp-Source: ABdhPJyZhFAd2YGphK/XY0dw4Ts+hRYzfAv9z9af30gG2TdYp94usAZUa4hOzH3Bs7xe5er/piUwHu2JAshTzk7ZpgE= X-Received: by 2002:a05:6402:34d5:b0:416:201f:c636 with SMTP id w21-20020a05640234d500b00416201fc636mr9133879edc.293.1646639914584; Sun, 06 Mar 2022 23:58:34 -0800 (PST) MIME-Version: 1.0 References: <3a6be84c8354f38754a9838670cc0319e84f29e8.1645626183.git.michal.simek@xilinx.com> <2d7eefa83c8c0129f7243a25de56a289e948f6c6.1645626183.git.michal.simek@xilinx.com> In-Reply-To: <2d7eefa83c8c0129f7243a25de56a289e948f6c6.1645626183.git.michal.simek@xilinx.com> From: Michal Simek Date: Mon, 7 Mar 2022 08:58:23 +0100 Message-ID: Subject: Re: [PATCH 2/2] pinctrl: zynqmp: Add pinctrl driver To: U-Boot , git Cc: Ashok Reddy Soma , Dylan Hung , Mark Kettenis , Ryan Chen , Yuan Fang Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean st 23. 2. 2022 v 15:23 odes=C3=ADlatel Michal Simek napsal: > > From: Ashok Reddy Soma > > 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 > Signed-off-by: Michal Simek > --- > > 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 p= erform > basic GPIO functions, such as reading the current value of a pi= n. > + > +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 u= ses > + Generic Pinctrl framework and is compatible with the Linux driv= er, > + 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) +=3D pinctrl-sti.o > obj-$(CONFIG_PINCTRL_STM32) +=3D pinctrl_stm32.o > obj-$(CONFIG_$(SPL_)PINCTRL_STMFX) +=3D pinctrl-stmfx.o > obj-y +=3D broadcom/ > +obj-$(CONFIG_PINCTRL_ZYNQMP) +=3D pinctrl-zynqmp.o > diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-z= ynqmp.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 > + * Michal Simek > + * > + * Copyright (C) 2021 Xilinx, Inc. All rights reserved. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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 na= me > + * for group and function. This way it is compatible with the Linux Kern= el > + * 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) allow= s > + * to select schmitt or cmos input for MIO p= ins > + */ > +enum zynqmp_pin_config_param { > + PIN_CONFIG_IOSTANDARD =3D 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 =3D xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, ret_= payload); > + if (ret) > + return ret; > + > + *out =3D 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 =3D xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param= , 0, 0, ret_payload); > + if (ret) { > + printf("%s failed\n", __func__); > + return ret; > + } > + > + *value =3D 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 =3D 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 =3D 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 *g= roups) > +{ > + int ret; > + u32 ret_payload[PAYLOAD_ARG_CNT]; > + > + ret =3D xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCT= ION_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] =3D {0}; > + int ret, index, i; > + > + fgroups =3D kcalloc(func->ngroups, sizeof(*fgroups), GFP_KERNEL); > + if (!fgroups) > + return -ENOMEM; > + > + for (index =3D 0; index < func->ngroups; index +=3D NUM_GROUPS_PE= R_RESP) { > + ret =3D zynqmp_pinctrl_get_function_groups(fid, index, re= sp); > + if (ret) > + return ret; > + > + for (i =3D 0; i < NUM_GROUPS_PER_RESP; i++) { > + if (resp[i] =3D=3D (u16)NA_GROUP) > + goto done; > + if (resp[i] =3D=3D (u16)RESERVED_GROUP) > + continue; > + > + snprintf(name, MAX_GROUP_NAME_LEN, "%s_%d_grp", > + func->name, index + i); > + fgroups[index + i] =3D strdup(name); > + > + snprintf(name, MAX_GROUP_NAME_LEN, "%s_%d_grp", > + func->name, index + i); > + groups[resp[i]].name =3D strdup(name); > + } > + } > +done: > + func->groups =3D 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 =3D xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_PIN_G= ROUPS, > + 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 *grou= p, > + unsigned int pin) > +{ > + group->pins[group->npins++] =3D pin; > +} > + > +static int zynqmp_pinctrl_create_pin_groups(struct zynqmp_pctrl_group *g= roups, > + unsigned int pin) > +{ > + u16 resp[NUM_GROUPS_PER_RESP] =3D {0}; > + int ret, i, index =3D 0; > + > + do { > + ret =3D zynqmp_pinctrl_get_pin_groups(pin, index, resp); > + if (ret) > + return ret; > + > + for (i =3D 0; i < NUM_GROUPS_PER_RESP; i++) { > + if (resp[i] =3D=3D (u16)NA_GROUP) > + goto done; > + if (resp[i] =3D=3D (u16)RESERVED_GROUP) > + continue; > + zynqmp_pinctrl_group_add_pin(&groups[resp[i]], pi= n); > + } > + index +=3D NUM_GROUPS_PER_RESP; > + } while (index <=3D MAX_PIN_GROUPS); > + > +done: > + return ret; > +} > + > +static int zynqmp_pinctrl_probe(struct udevice *dev) > +{ > + struct zynqmp_pinctrl_priv *priv =3D dev_get_priv(dev); > + int ret, i; > + u32 pin; > + u32 ret_payload[PAYLOAD_ARG_CNT]; > + > + /* Get number of pins first */ > + ret =3D 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 =3D 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 =3D kzalloc(sizeof(*priv->funcs) * priv->nfuncs, GFP_= KERNEL); > + if (!priv->funcs) > + return -ENOMEM; > + > + for (i =3D 0; i < priv->nfuncs; i++) { > + /* Get function name for the function and fill */ > + xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCT= ION_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 functi= on */ > + xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_NUM_F= UNCTION_GROUPS, > + i, 0, 0, ret_payload); > + > + priv->funcs[i].ngroups =3D ret_payload[1]; > + priv->ngroups +=3D priv->funcs[i].ngroups; > + } > + > + /* Prepare all groups */ > + priv->groups =3D kzalloc(sizeof(*priv->groups) * priv->ngroups, > + GFP_KERNEL); > + if (!priv->groups) > + return -ENOMEM; > + > + for (i =3D 0; i < priv->nfuncs; i++) { > + ret =3D zynqmp_pinctrl_prepare_func_groups(i, &priv->func= s[i], > + priv->groups); > + if (ret) { > + printf("Failed to prepare_func_groups\n"); > + return ret; > + } > + } > + > + for (pin =3D 0; pin < priv->npins; pin++) { > + ret =3D zynqmp_pinctrl_create_pin_groups(priv->groups, pi= n); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > +static int zynqmp_pinctrl_get_functions_count(struct udevice *dev) > +{ > + struct zynqmp_pinctrl_priv *priv =3D 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 =3D 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 =3D 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 =3D 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 sel= ector, > + unsigned int func_selector) > +{ > + int i; > + struct zynqmp_pinctrl_priv *priv =3D dev_get_priv(dev); > + const struct zynqmp_pctrl_group *pgrp =3D &priv->groups[selector]= ; > + > + for (i =3D 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 =3D 0; > + unsigned int value; > + > + switch (param) { > + case PIN_CONFIG_SLEW_RATE: > + param =3D PM_PINCTRL_CONFIG_SLEW_RATE; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, arg); > + break; > + case PIN_CONFIG_BIAS_PULL_UP: > + param =3D PM_PINCTRL_CONFIG_PULL_CTRL; > + arg =3D PM_PINCTRL_BIAS_PULL_UP; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, arg); > + break; > + case PIN_CONFIG_BIAS_PULL_DOWN: > + param =3D PM_PINCTRL_CONFIG_PULL_CTRL; > + arg =3D PM_PINCTRL_BIAS_PULL_DOWN; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, arg); > + break; > + case PIN_CONFIG_BIAS_DISABLE: > + param =3D PM_PINCTRL_CONFIG_BIAS_STATUS; > + arg =3D PM_PINCTRL_BIAS_DISABLE; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, arg); > + break; > + case PIN_CONFIG_SCHMITTCMOS: > + param =3D PM_PINCTRL_CONFIG_SCHMITT_CMOS; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, arg); > + break; > + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: > + param =3D PM_PINCTRL_CONFIG_SCHMITT_CMOS; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, arg); > + break; > + case PIN_CONFIG_DRIVE_STRENGTH: > + switch (arg) { > + case DRIVE_STRENGTH_2MA: > + value =3D PM_PINCTRL_DRIVE_STRENGTH_2MA; > + break; > + case DRIVE_STRENGTH_4MA: > + value =3D PM_PINCTRL_DRIVE_STRENGTH_4MA; > + break; > + case DRIVE_STRENGTH_8MA: > + value =3D PM_PINCTRL_DRIVE_STRENGTH_8MA; > + break; > + case DRIVE_STRENGTH_12MA: > + value =3D PM_PINCTRL_DRIVE_STRENGTH_12MA; > + break; > + default: > + /* Invalid drive strength */ > + dev_warn(dev, "Invalid drive strength for pin %d\= n", pin); > + return -EINVAL; > + } > + > + param =3D PM_PINCTRL_CONFIG_DRIVE_STRENGTH; > + ret =3D zynqmp_pm_pinctrl_set_config(pin, param, value); > + break; > + case PIN_CONFIG_IOSTANDARD: > + param =3D PM_PINCTRL_CONFIG_VOLTAGE_STATUS; > + ret =3D zynqmp_pm_pinctrl_get_config(pin, param, &value); > + if (arg !=3D value) > + dev_warn(dev, "Invalid IO Standard requested for = pin %d\n", > + pin); > + break; > + case PIN_CONFIG_POWER_SOURCE: > + param =3D PM_PINCTRL_CONFIG_VOLTAGE_STATUS; > + ret =3D zynqmp_pm_pinctrl_get_config(pin, param, &value); > + if (arg !=3D 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 =3D 0; > + break; > + default: > + dev_warn(dev, "unsupported configuration parameter '%u'\n= ", > + param); > + ret =3D -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 =3D dev_get_priv(dev); > + const struct zynqmp_pctrl_group *pgrp =3D &priv->groups[group_sel= ector]; > + > + for (i =3D 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 =3D 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_RAT= E, > + &pinmux.slew); > + zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_BIAS_STA= TUS, > + &pinmux.bias); > + zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_PULL_CTR= L, > + &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_ST= RENGTH, > + &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 =3D DRIVE_STRENGTH_2MA; > + break; > + case PM_PINCTRL_DRIVE_STRENGTH_4MA: > + pinmux.drive_strength =3D DRIVE_STRENGTH_4MA; > + break; > + case PM_PINCTRL_DRIVE_STRENGTH_8MA: > + pinmux.drive_strength =3D DRIVE_STRENGTH_8MA; > + break; > + case PM_PINCTRL_DRIVE_STRENGTH_12MA: > + pinmux.drive_strength =3D 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 =3D 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 =3D dev_get_priv(dev); > + > + return priv->groups[selector].name; > +} > + > +static const struct pinconf_param zynqmp_conf_params[] =3D { > + { "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_SC= HMITT}, > +}; > + > +static struct pinctrl_ops zynqmp_pinctrl_ops =3D { > + .get_pins_count =3D zynqmp_pinctrl_get_pins_count, > + .get_pin_name =3D zynqmp_pinctrl_get_pin_name, > + .get_pin_muxing =3D zynqmp_pinctrl_get_pin_muxing, > + .set_state =3D pinctrl_generic_set_state, > + .get_groups_count =3D zynqmp_pinctrl_get_groups_count, > + .get_group_name =3D zynqmp_pinctrl_get_group_name, > + .get_functions_count =3D zynqmp_pinctrl_get_functions_count, > + .get_function_name =3D zynqmp_pinctrl_get_function_name, > + .pinmux_group_set =3D zynqmp_pinmux_group_set, > + .pinmux_set =3D zynqmp_pinmux_set, > + .pinconf_params =3D zynqmp_conf_params, > + .pinconf_group_set =3D zynqmp_pinconf_group_set, > + .pinconf_set =3D zynqmp_pinconf_set, > + .pinconf_num_params =3D ARRAY_SIZE(zynqmp_conf_params), > +}; > + > +static const struct udevice_id zynqmp_pinctrl_ids[] =3D { > + { .compatible =3D "xlnx,zynqmp-pinctrl" }, > + { } > +}; > + > +U_BOOT_DRIVER(pinctrl_zynqmp) =3D { > + .name =3D "zynqmp-pinctrl", > + .id =3D UCLASS_PINCTRL, > + .of_match =3D zynqmp_pinctrl_ids, > + .priv_auto =3D sizeof(struct zynqmp_pinctrl_priv), > + .ops =3D &zynqmp_pinctrl_ops, > + .probe =3D 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 =3D 13, > }; > > +enum pm_pinctrl_config_param { > + PM_PINCTRL_CONFIG_SLEW_RATE =3D 0, > + PM_PINCTRL_CONFIG_BIAS_STATUS =3D 1, > + PM_PINCTRL_CONFIG_PULL_CTRL =3D 2, > + PM_PINCTRL_CONFIG_SCHMITT_CMOS =3D 3, > + PM_PINCTRL_CONFIG_DRIVE_STRENGTH =3D 4, > + PM_PINCTRL_CONFIG_VOLTAGE_STATUS =3D 5, > + PM_PINCTRL_CONFIG_TRI_STATE =3D 6, > + PM_PINCTRL_CONFIG_MAX =3D 7, > +}; > + > +enum pm_pinctrl_slew_rate { > + PM_PINCTRL_SLEW_RATE_FAST =3D 0, > + PM_PINCTRL_SLEW_RATE_SLOW =3D 1, > +}; > + > +enum pm_pinctrl_bias_status { > + PM_PINCTRL_BIAS_DISABLE =3D 0, > + PM_PINCTRL_BIAS_ENABLE =3D 1, > +}; > + > +enum pm_pinctrl_pull_ctrl { > + PM_PINCTRL_BIAS_PULL_DOWN =3D 0, > + PM_PINCTRL_BIAS_PULL_UP =3D 1, > +}; > + > +enum pm_pinctrl_schmitt_cmos { > + PM_PINCTRL_INPUT_TYPE_CMOS =3D 0, > + PM_PINCTRL_INPUT_TYPE_SCHMITT =3D 1, > +}; > + > +enum pm_pinctrl_drive_strength { > + PM_PINCTRL_DRIVE_STRENGTH_2MA =3D 0, > + PM_PINCTRL_DRIVE_STRENGTH_4MA =3D 1, > + PM_PINCTRL_DRIVE_STRENGTH_8MA =3D 2, > + PM_PINCTRL_DRIVE_STRENGTH_12MA =3D 3, > +}; > + > +enum pm_pinctrl_tri_state { > + PM_PINCTRL_TRI_STATE_DISABLE =3D 0, > + PM_PINCTRL_TRI_STATE_ENABLE =3D 1, > +}; > + > enum zynqmp_pm_reset_action { > PM_RESET_ACTION_RELEASE =3D 0, > PM_RESET_ACTION_ASSERT =3D 1, > -- > 2.35.1 > Applied. M --=20 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