RE: [PATCH v2 2/2] pinctrl: zynqmp: Support muxing individual pins

From: Potthuri, Sai Krishna
Date: Mon Jun 10 2024 - 08:16:17 EST


Hi Sean,

> -----Original Message-----
> From: Sean Anderson <sean.anderson@xxxxxxxxx>
> Sent: Monday, May 20, 2024 8:34 PM
> To: Linus Walleij <linus.walleij@xxxxxxxxxx>; Simek, Michal
> <michal.simek@xxxxxxx>; linux-gpio@xxxxxxxxxxxxxxx
> Cc: Potthuri, Sai Krishna <sai.krishna.potthuri@xxxxxxx>; linux-
> kernel@xxxxxxxxxxxxxxx; Andy Shevchenko <andy.shevchenko@xxxxxxxxx>;
> linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; Sean Anderson
> <sean.anderson@xxxxxxxxx>
> Subject: [PATCH v2 2/2] pinctrl: zynqmp: Support muxing individual pins
>
> While muxing groups of pins at once can be convenient for large interfaces,
> it can also be rigid. This is because the group is set to all pins which support
> a particular function, even though not all pins may be used. For example,
> the sdhci0 function may be used with a 8-bit eMMC, 4-bit SD card, or even a
> 1-bit SD card. In these cases, the extra pins may be repurposed for other
> uses, but this is not currently allowed.
>
> There is not too much point in pin "groups" when there are not actual pin
> groups at the hardware level. The pins can all be muxed individually, so
> there's no point in adding artificial groups on top.
> Just mux the pins like the hardware allows.
>
> To this effect, add a new group for each pin which can be muxed. These
> groups are part of each function the pin can be muxed to. We treat group
> selectors beyond the number of groups as "pin" groups. To set this up, we
> initialize groups before functions, and then create a bitmap of used pins for
> each function. These used pins are appended to the function's list of
> groups.
>
> Signed-off-by: Sean Anderson <sean.anderson@xxxxxxxxx>
> ---
>
> Changes in v2:
> - Use __set_bit instead of set_bit
> - Use size_add when calculating the number of kcalloc members
> - Expand commit message with some more motivation
>
> drivers/pinctrl/pinctrl-zynqmp.c | 61 ++++++++++++++++++++++----------
> 1 file changed, 43 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-
> zynqmp.c
> index 5c46b7d7ebcb..7cc1e43fb07c 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/bitmap.h>
> #include <linux/init.h>
> #include <linux/module.h>
> #include <linux/of_address.h>
> @@ -97,7 +98,7 @@ static int zynqmp_pctrl_get_groups_count(struct
> pinctrl_dev *pctldev) {
> struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
>
> - return pctrl->ngroups;
> + return pctrl->ngroups + zynqmp_desc.npins;
> }
>
> static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev
> *pctldev, @@ -105,7 +106,10 @@ static const char
> *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev, {
> struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
>
> - return pctrl->groups[selector].name;
> + if (selector < pctrl->ngroups)
> + return pctrl->groups[selector].name;
> +
> + return zynqmp_desc.pins[selector - pctrl->ngroups].name;
> }
>
> static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev, @@ -
> 115,8 +119,13 @@ static int zynqmp_pctrl_get_group_pins(struct
> pinctrl_dev *pctldev, {
> struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
>
> - *pins = pctrl->groups[selector].pins;
> - *npins = pctrl->groups[selector].npins;
> + if (selector < pctrl->ngroups) {
> + *pins = pctrl->groups[selector].pins;
> + *npins = pctrl->groups[selector].npins;
> + } else {
> + *pins = &zynqmp_desc.pins[selector - pctrl-
> >ngroups].number;
> + *npins = 1;
> + }
>
> return 0;
> }
> @@ -560,10 +569,12 @@ static int
> zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid, {
> u16 resp[NUM_GROUPS_PER_RESP] = {0};
> const char **fgroups;
> - int ret, index, i;
> + int ret, index, i, pin;
> + unsigned int npins;
> + unsigned long *used_pins __free(bitmap) =
> + bitmap_zalloc(zynqmp_desc.npins, GFP_KERNEL);
>
> - fgroups = devm_kcalloc(dev, func->ngroups, sizeof(*fgroups),
> GFP_KERNEL);
> - if (!fgroups)
> + if (!used_pins)
> return -ENOMEM;
>
> for (index = 0; index < func->ngroups; index +=
> NUM_GROUPS_PER_RESP) { @@ -578,23 +589,37 @@ static int
> zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid,
> if (resp[i] == RESERVED_GROUP)
> continue;
>
> - fgroups[index + i] = devm_kasprintf(dev,
> GFP_KERNEL,
> - "%s_%d_grp",
> - func->name,
> - index + i);
> - if (!fgroups[index + i])
> - return -ENOMEM;
> -
> groups[resp[i]].name = devm_kasprintf(dev,
> GFP_KERNEL,
> "%s_%d_grp",
> func->name,
> index + i);
> 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);
> }
> }
> done:
> + npins = bitmap_weight(used_pins, zynqmp_desc.npins);
> + fgroups = devm_kcalloc(dev, size_add(func->ngroups, npins),
> + sizeof(*fgroups), GFP_KERNEL);
> + if (!fgroups)
> + return -ENOMEM;
> +
> + for (i = 0; i < func->ngroups; i++) {
> + fgroups[i] = devm_kasprintf(dev, GFP_KERNEL, "%s_%d_grp",
> + func->name, i);
> + if (!fgroups[i])
> + return -ENOMEM;
> + }
> +
> + pin = 0;
> + for_each_set_bit(pin, used_pins, zynqmp_desc.npins)
> + fgroups[i++] = zynqmp_desc.pins[pin].name;
> +
> func->groups = fgroups;
> + func->ngroups += npins;
>
> return 0;
> }
> @@ -772,6 +797,10 @@ static int
> zynqmp_pinctrl_prepare_function_info(struct device *dev,
> if (!groups)
> return -ENOMEM;
>
> + ret = zynqmp_pinctrl_prepare_group_pins(dev, groups, pctrl-
> >ngroups);
> + if (ret)
> + return ret;
> +
> for (i = 0; i < pctrl->nfuncs; i++) {
> ret = zynqmp_pinctrl_prepare_func_groups(dev, i, &funcs[i],
> groups);
> @@ -779,10 +808,6 @@ static int
> zynqmp_pinctrl_prepare_function_info(struct device *dev,
> return ret;
> }
>
> - ret = zynqmp_pinctrl_prepare_group_pins(dev, groups, pctrl-
> >ngroups);
> - if (ret)
> - return ret;
> -
> pctrl->funcs = funcs;
> pctrl->groups = groups;
>
While testing this patch, observed that some more changes required in the
other functions like set_mux, pin_config_group_set. Pasted the diff below.


diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
index 636e56f7cd92..c82074819be3 100644
--- a/drivers/pinctrl/pinctrl-zynqmp.c
+++ b/drivers/pinctrl/pinctrl-zynqmp.c
@@ -206,12 +206,18 @@ static int zynqmp_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int function,
unsigned int group)
{
- struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- const struct zynqmp_pctrl_group *pgrp = &pctrl->groups[group];
+ const unsigned *pins;
+ unsigned npins;
int ret, i;

- for (i = 0; i < pgrp->npins; i++) {
- unsigned int pin = pgrp->pins[i];
+ ret = zynqmp_pctrl_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret) {
+ dev_err(pctldev->dev, "Get group pins failed for group %u\n", group);
+ return ret;
+ }
+
+ for (i = 0; i < npins; i++) {
+ unsigned int pin = pins[i];

ret = zynqmp_pm_pinctrl_set_function(pin, function);
if (ret) {
@@ -476,13 +482,18 @@ static int zynqmp_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned long *configs,
unsigned int num_configs)
{
- int i, ret;
- struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- const struct zynqmp_pctrl_group *pgrp = &pctrl->groups[selector];
-
- for (i = 0; i < pgrp->npins; i++) {
- ret = zynqmp_pinconf_cfg_set(pctldev, pgrp->pins[i], configs,
- num_configs);
+ const unsigned *pins;
+ unsigned npins;
+ int i, ret;
+
+ ret = zynqmp_pctrl_get_group_pins(pctldev, selector, &pins, &npins);
+ if (ret) {
+ dev_err(pctldev->dev, "Get group pins failed for group %u\n", selector);
+ return ret;
+ }
+
+ for (i = 0; i < npins; i++) {
+ ret = zynqmp_pinconf_cfg_set(pctldev, pins[i], configs, num_configs);
if (ret)
return ret;
}

Regards
Sai Krishna