mbox series

[v4,0/2] Support Nvidia BlueField-3 GPIO driver and pin controller

Message ID cover.1676668853.git.asmaa@nvidia.com
Headers show
Series Support Nvidia BlueField-3 GPIO driver and pin controller | expand

Message

Asmaa Mnebhi Feb. 17, 2023, 9:26 p.m. UTC
Support the BlueField-3 SoC GPIO driver for handling interrupts and
providing the option to change the direction and value of a GPIO.
Support the BlueField-3 SoC pin controller driver for allowing a
select number of GPIO pins to be manipulated from userspace or
the kernel.

The gpio-mlxbf3.c driver handles hardware registers and logic
that are different from gpio-mlxbf.c and gpio-mlxbf2.c.
For that reason, we have separate drivers for each generation.

Changes from v3->v4:
gpio-mlxbf3.c:
- Update the Kconfig file so that it is conform with checkpatch
- Remove unncessary headers and add missing header inclusions
- Make irq_chip struct static and const
- Replace generic_handle_irq(irq_find_mapping) with
  generic_handle_domain_irq
- Simplify logic in irq_set_type
- Replace valid_mask with gpio-reserved-ranges
- Cleanup code

pinctrl-mlxbf.c:
- Cleanup code
- Update the Kconfig file so that it is conform with checkpatch
- Remove unncessary headers and add missing header inclusions

Asmaa Mnebhi (2):
  gpio: gpio-mlxbf3: Add gpio driver support
  pinctrl: pinctrl-mlxbf: Add pinctrl driver support

 drivers/gpio/Kconfig            |  12 ++
 drivers/gpio/Makefile           |   1 +
 drivers/gpio/gpio-mlxbf3.c      | 230 ++++++++++++++++++++++
 drivers/pinctrl/Kconfig         |  14 ++
 drivers/pinctrl/Makefile        |   1 +
 drivers/pinctrl/pinctrl-mlxbf.c | 338 ++++++++++++++++++++++++++++++++
 6 files changed, 596 insertions(+)
 create mode 100644 drivers/gpio/gpio-mlxbf3.c
 create mode 100644 drivers/pinctrl/pinctrl-mlxbf.c

Comments

Andy Shevchenko Feb. 17, 2023, 11:07 p.m. UTC | #1
On Fri, Feb 17, 2023 at 11:27 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:
>
> Add support for the BlueField-3 SoC GPIO driver.
> This driver configures and handles GPIO interrupts. It also enables a user
> to manipulate certain GPIO pins via libgpiod tools or other kernel drivers.
> The usables pins are defined via the gpio-reserved-ranges property.

Probably

"gpio-reserved-ranges"

(in double quotes).

...

> +       depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST)

But do you really need the ACPI dependency? I don't see a single bit
of it in the driver.
(Yes, I know about IDs.)

Also, how 64BIT is needed for testing?

...

> +#include <linux/version.h>

I believe it's included automatically. Please, double check the header
inclusions to make sure you don't have some spurious ones in the list.

> +struct mlxbf3_gpio_context {
> +       struct gpio_chip gc;
> +
> +       /* YU GPIO block address */
> +       void __iomem *gpio_io;
> +
> +       /* YU GPIO cause block address */
> +       void __iomem *gpio_cause_io;
> +};

...

> +       int offset = irqd_to_hwirq(irqd);

It returns irq_hw_number_t IIRC. It's an unsigned type. Otherwise you
may have interesting effects.

...

> +       int offset = irqd_to_hwirq(irqd);

Ditto.

...

> +       raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
> +
> +       switch (type & IRQ_TYPE_SENSE_MASK) {
> +       case IRQ_TYPE_EDGE_BOTH:
> +               val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
> +               val |= BIT(offset);
> +               writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
> +               val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
> +               val |= BIT(offset);
> +               writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
> +               break;
> +       case IRQ_TYPE_EDGE_RISING:
> +               val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
> +               val |= BIT(offset);
> +               writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
> +               break;
> +       case IRQ_TYPE_EDGE_FALLING:
> +               val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
> +               val |= BIT(offset);
> +               writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
> +               break;
> +       default:

Dead lock starts here.

> +               return -EINVAL;
> +       }
> +
> +       raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);

...

> +       irq_set_handler_locked(irqd, handle_simple_irq);

Why not using propert handler type (edge)?

...

> +static const struct irq_chip gpio_mlxbf3_irqchip = {
> +       .name = "MLNXBF33",
> +       .irq_set_type = mlxbf3_gpio_irq_set_type,
> +       .irq_enable = mlxbf3_gpio_irq_enable,
> +       .irq_disable = mlxbf3_gpio_irq_disable,
> +};

Seems missing two things (dunno if bgpio_init() helps with that):
- IMMUTABLE flag
- actual calls to enable and disable IRQs for internal GPIO library usage

See other drivers how it's done. There are even plenty of patches to
enable this thing separately.

...

> +static int
> +mlxbf3_gpio_probe(struct platform_device *pdev)

Doesn't it perfectly fit one line?

...

> +       npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK;
> +       device_property_read_u32(dev, "npins", &npins);

I don't see DT bindings for this property (being added in this
series). Is it already established one?

...

> +               girq->default_type = IRQ_TYPE_NONE;

Assigning handle_bad_irq() is missing.
Andy Shevchenko Feb. 17, 2023, 11:24 p.m. UTC | #2
On Fri, Feb 17, 2023 at 11:27 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:
>
> NVIDIA BlueField-3 SoC has a few pins that can be used as GPIOs
> or take the default hardware functionality. Add a driver for
> the pinmuxing.

pin muxing

...

> +++ b/drivers/pinctrl/pinctrl-mlxbf.c

Wondering if it would be better to match the GPIO driver naming
schema, i.e. by adding 3. In this case the additional explanation in
Kconfig help won't be necessary.

...

> +#define MLXBF_GPIO0_FW_CONTROL_SET   0
> +#define MLXBF_GPIO0_FW_CONTROL_CLEAR 0x14
> +#define MLXBF_GPIO1_FW_CONTROL_SET   0x80
> +#define MLXBF_GPIO1_FW_CONTROL_CLEAR 0x94

Unclear if these are commands or register offsets. If they are of the
same type (semantically), make them fixed width, e.g., 0x00.

...

> +enum {
> +       MLXBF_GPIO_HW_MODE,
> +       MLXBF_GPIO_SW_MODE

I would leave a comma here as it might be extended in the future.

> +};

...

> +static const char * const mlxbf_pinctrl_single_group_names[] = {
> +       "gpio0", "gpio1",  "gpio2",  "gpio3",  "gpio4",  "gpio5",  "gpio6",
> +       "gpio7", "gpio8",  "gpio9",  "gpio10", "gpio11", "gpio12", "gpio13",
> +       "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20",
> +       "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27",
> +       "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34",
> +       "gpio35", "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41",
> +       "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48",
> +       "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55"

Ditto.
Can you group by 8?

> +};
> +
> +/* Set of pin numbers for single-pin groups */
> +static const unsigned int mlxbf_pinctrl_single_group_pins[] = {
> +       0,  1,  2,  3,  4,  5,  6,
> +       7,  8,  9, 10, 11, 12, 13,
> +       14, 15, 16, 17, 18, 19, 20,
> +       21, 22, 23, 24, 25, 26, 27,
> +       28, 29, 30, 31, 32, 33, 34,
> +       35, 36, 37, 38, 39, 40, 41,
> +       42, 43, 44, 45, 46, 47, 48,
> +       49, 50, 51, 52, 53, 54, 55,

Group by 8 which is the more natural length of subarray per line.

Is it just 1:1 to the index? If so, why do you need this table at all?

> +};

...

> +static const struct {
> +       const char *name;
> +       const char * const *group_names;

Use this instead
https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git/tree/include/linux/pinctrl/pinctrl.h?h=devel#n215
and this
https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git/tree/include/linux/pinctrl/pinctrl.h?h=devel#n222

> +} mlxbf_pmx_funcs[] = {

> +};

...

> +{
> +       struct mlxbf_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev);
> +
> +       /* disable GPIO functionality by giving control back to hardware */
> +       if (offset < MLXBF_NGPIOS_GPIO0)
> +               writel(BIT(offset), priv->base + MLXBF_GPIO0_FW_CONTROL_CLEAR);
> +       else
> +               writel(BIT(offset % MLXBF_NGPIOS_GPIO0), priv->base + MLXBF_GPIO1_FW_CONTROL_CLEAR);

> +

Redundant blank line.

> +}

...

> +static_assert(ARRAY_SIZE(mlxbf_pinctrl_single_group_names) ==
> +             ARRAY_SIZE(mlxbf_pinctrl_single_group_pins));

I would put it on a single line, but it's up to you.

...

> +       struct resource *res;

Useless?

...

> +       /* This resource is shared so use devm_ioremap */

Can you elaborate on who actually requests the region? And why is it
not _this_ driver?

> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!res)
> +               return -ENODEV;

...

> +       ret = devm_pinctrl_register_and_init(priv->dev,

Is the priv->dev different from dev?

> +                                            &mlxbf_pin_desc,
> +                                            priv,
> +                                            &priv->pctl);
> +       if (ret)
> +               return dev_err_probe(dev, ret, "Failed to register pinctrl\n");

...

> +       pinctrl_add_gpio_range(priv->pctl, &mlxbf_pinctrl_gpio_ranges[0]);
> +       pinctrl_add_gpio_range(priv->pctl, &mlxbf_pinctrl_gpio_ranges[1]);

pinctrl_add_gpio_ranges() ?

--
With Best Regards,
Andy Shevchenko
Asmaa Mnebhi Feb. 22, 2023, 6:40 p.m. UTC | #3
> +static const struct irq_chip gpio_mlxbf3_irqchip = {
> +       .name = "MLNXBF33",
> +       .irq_set_type = mlxbf3_gpio_irq_set_type,
> +       .irq_enable = mlxbf3_gpio_irq_enable,
> +       .irq_disable = mlxbf3_gpio_irq_disable, };

Seems missing two things (dunno if bgpio_init() helps with that):
- IMMUTABLE flag
- actual calls to enable and disable IRQs for internal GPIO library usage
See other drivers how it's done. There are even plenty of patches to enable this thing separately.

I saw that in other drivers only irq_enable and irq_disable are defined. Example in gpio-davinci.c:
static struct irq_chip gpio_irqchip = {
.name           = "GPIO",
.irq_enable     = gpio_irq_enable,
.irq_disable    = gpio_irq_disable,
.irq_set_type   = gpio_irq_type,
.flags          = IRQCHIP_SET_TYPE_MASKED,
};

Which I think is ok due to the following logic:

gpiochip_add_irqchip calls
gpiochip_set_irq_hooks which contains the following logic:

if (irqchip->irq_disable) {
                 gc->irq.irq_disable = irqchip->irq_disable;
                 irqchip->irq_disable = gpiochip_irq_disable;
} else {
                 gc->irq.irq_mask = irqchip->irq_mask;
                 irqchip->irq_mask = gpiochip_irq_mask;
}
if (irqchip->irq_enable) {
                 gc->irq.irq_enable = irqchip->irq_enable;
                 irqchip->irq_enable = gpiochip_irq_enable;
} else {
                 gc->irq.irq_unmask = irqchip->irq_unmask;
                 irqchip->irq_unmask = gpiochip_irq_unmask;
}

So it doesn’t seem like we need to define irq_mask/unmask if we have irq_enable/disable?

> +       npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK;
> +       device_property_read_u32(dev, "npins", &npins);

I don't see DT bindings for this property (being added in this series). Is it already established one?

Ah that’s my bad. The property should be called "ngpios" like in the DT documentation. Will fix.

--
With Best Regards,
Andy Shevchenko
Andy Shevchenko Feb. 23, 2023, 11:06 a.m. UTC | #4
On Wed, Feb 22, 2023 at 8:40 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:

First of all, please, please, fix your email client!
It's so hard to distinguish my own words from yours.

> > +static const struct irq_chip gpio_mlxbf3_irqchip = {
> > +       .name = "MLNXBF33",
> > +       .irq_set_type = mlxbf3_gpio_irq_set_type,
> > +       .irq_enable = mlxbf3_gpio_irq_enable,
> > +       .irq_disable = mlxbf3_gpio_irq_disable, };
>
> Seems missing two things (dunno if bgpio_init() helps with that):
> - IMMUTABLE flag
> - actual calls to enable and disable IRQs for internal GPIO library usage
> See other drivers how it's done. There are even plenty of patches to enable this thing separately.
>
> I saw that in other drivers only irq_enable and irq_disable are defined. Example in gpio-davinci.c:
> static struct irq_chip gpio_irqchip = {
> .name           = "GPIO",
> .irq_enable     = gpio_irq_enable,
> .irq_disable    = gpio_irq_disable,
> .irq_set_type   = gpio_irq_type,
> .flags          = IRQCHIP_SET_TYPE_MASKED,
> };
>
> Which I think is ok due to the following logic:
>
> gpiochip_add_irqchip calls
> gpiochip_set_irq_hooks which contains the following logic:
>
> if (irqchip->irq_disable) {
>                  gc->irq.irq_disable = irqchip->irq_disable;
>                  irqchip->irq_disable = gpiochip_irq_disable;
> } else {
>                  gc->irq.irq_mask = irqchip->irq_mask;
>                  irqchip->irq_mask = gpiochip_irq_mask;
> }
> if (irqchip->irq_enable) {
>                  gc->irq.irq_enable = irqchip->irq_enable;
>                  irqchip->irq_enable = gpiochip_irq_enable;
> } else {
>                  gc->irq.irq_unmask = irqchip->irq_unmask;
>                  irqchip->irq_unmask = gpiochip_irq_unmask;
> }

The chips have another flag there:

        .flags          = IRQCHIP_IMMUTABLE,
       GPIOCHIP_IRQ_RESOURCE_HELPERS,

> So it doesn’t seem like we need to define irq_mask/unmask if we have irq_enable/disable?
>
> > +       npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK;
> > +       device_property_read_u32(dev, "npins", &npins);
>
> I don't see DT bindings for this property (being added in this series). Is it already established one?
>
> Ah that’s my bad. The property should be called "ngpios" like in the DT documentation. Will fix.

And why do you need it? What's a corner case that the GPIO library
doesn't handle yet?
Asmaa Mnebhi Feb. 23, 2023, 7:08 p.m. UTC | #5
> > > +       npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK;
> > > +       device_property_read_u32(dev, "npins", &npins);
> >
> > I don't see DT bindings for this property (being added in this series). Is it
> already established one?
> >
> > Ah that’s my bad. The property should be called "ngpios" like in the DT
> documentation. Will fix.
> 
> And why do you need it? What's a corner case that the GPIO library doesn't
> handle yet?

We have 2 gpiochips, gpiochip 0 supports 32 gpio pins and gpiochip 1 supports only 24 pins.
If I remove the logic from gpio-mlxbf3.c, the gpiolib.c logic will correctly set the ngpios = 32 for gpiochip 0 but will wrongly set ngpios=32 for gpiogchip 1:

gpiochip_add_data_with_key {
	[...]
	ngpios = gc->ngpio;
	if (ngpios == 0) {
		ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios);
		if (ret == -ENODATA)
			/*
			 * -ENODATA means that there is no property found and
			 * we want to issue the error message to the user.
			 * Besides that, we want to return different error code
			 * to state that supplied value is not valid.
			 */
			ngpios = 0;
		else if (ret)
			goto err_free_dev_name;

		gc->ngpio = ngpios;
	}
	[...]
}

bgpio_init {
	gc->bgpio_bits = sz * 8;
	gc->ngpio = gc->bgpio_bits;
}
Andy Shevchenko Feb. 23, 2023, 7:58 p.m. UTC | #6
On Thu, Feb 23, 2023 at 9:08 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:
>
> > > > +       npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK;
> > > > +       device_property_read_u32(dev, "npins", &npins);
> > >
> > > I don't see DT bindings for this property (being added in this series). Is it
> > already established one?
> > >
> > > Ah that’s my bad. The property should be called "ngpios" like in the DT
> > documentation. Will fix.
> >
> > And why do you need it? What's a corner case that the GPIO library doesn't
> > handle yet?
>
> We have 2 gpiochips, gpiochip 0 supports 32 gpio pins and gpiochip 1 supports only 24 pins.
> If I remove the logic from gpio-mlxbf3.c, the gpiolib.c logic will correctly set the ngpios = 32 for gpiochip 0 but will wrongly set ngpios=32 for gpiogchip 1:

So, either you need to have two entries in DT per chip or ngpios should be 56.
Asmaa Mnebhi Feb. 23, 2023, 10:51 p.m. UTC | #7
> >
> > > > > +       npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK;
> > > > > +       device_property_read_u32(dev, "npins", &npins);
> > > >
> > > > I don't see DT bindings for this property (being added in this
> > > > series). Is it
> > > already established one?
> > > >
> > > > Ah that’s my bad. The property should be called "ngpios" like in
> > > > the DT
> > > documentation. Will fix.
> > >
> > > And why do you need it? What's a corner case that the GPIO library
> > > doesn't handle yet?
> >
> > We have 2 gpiochips, gpiochip 0 supports 32 gpio pins and gpiochip 1
> supports only 24 pins.
> > If I remove the logic from gpio-mlxbf3.c, the gpiolib.c logic will correctly set
> the ngpios = 32 for gpiochip 0 but will wrongly set ngpios=32 for gpiogchip 1:
> 
> So, either you need to have two entries in DT per chip or ngpios should be 56.
> 
I already have 2 entries in my ACPI table, in the first entry, ngpios = 32 and in the second entry ngpios = 24.
Gpiochip_add_data_with_keys only reads the ngpios property if (ngpios == 0) which is not the case when 
bgpio_init is called. bgpio_init uses "sz" argument to populate the ngpio in bgpio_init, which is not what we want.
Andy Shevchenko Feb. 24, 2023, 9:47 a.m. UTC | #8
On Fri, Feb 24, 2023 at 12:51 AM Asmaa Mnebhi <asmaa@nvidia.com> wrote:

...

> > > > > Ah that’s my bad. The property should be called "ngpios" like in
> > > > > the DT
> > > > documentation. Will fix.
> > > >
> > > > And why do you need it? What's a corner case that the GPIO library
> > > > doesn't handle yet?
> > >
> > > We have 2 gpiochips, gpiochip 0 supports 32 gpio pins and gpiochip 1
> > supports only 24 pins.
> > > If I remove the logic from gpio-mlxbf3.c, the gpiolib.c logic will correctly set
> > the ngpios = 32 for gpiochip 0 but will wrongly set ngpios=32 for gpiogchip 1:
> >
> > So, either you need to have two entries in DT per chip or ngpios should be 56.
> >
> I already have 2 entries in my ACPI table, in the first entry, ngpios = 32 and in the second entry ngpios = 24.

Can you show the DSDT excerpt of this device? (Also including the
pieces for pin control)

Is this a table of the device in the wild?

> Gpiochip_add_data_with_keys only reads the ngpios property if (ngpios == 0) which is not the case when
> bgpio_init is called. bgpio_init uses "sz" argument to populate the ngpio in bgpio_init, which is not what we want.

Maybe bgpio_init() is not a good API for your case?

--
With Best Regards,
Andy Shevchenko
Asmaa Mnebhi Feb. 24, 2023, 2:42 p.m. UTC | #9
> > > > > > Ah that’s my bad. The property should be called "ngpios" like
> > > > > > in the DT
> > > > > documentation. Will fix.
> > > > >
> > > > > And why do you need it? What's a corner case that the GPIO
> > > > > library doesn't handle yet?
> > > >
> > > > We have 2 gpiochips, gpiochip 0 supports 32 gpio pins and gpiochip
> > > > 1
> > > supports only 24 pins.
> > > > If I remove the logic from gpio-mlxbf3.c, the gpiolib.c logic will
> > > > correctly set
> > > the ngpios = 32 for gpiochip 0 but will wrongly set ngpios=32 for gpiogchip
> 1:
> > >
> > > So, either you need to have two entries in DT per chip or ngpios should be
> 56.
> > >
> > I already have 2 entries in my ACPI table, in the first entry, ngpios = 32 and
> in the second entry ngpios = 24.
> 
> Can you show the DSDT excerpt of this device? (Also including the pieces for
> pin control)

Our ACPI tables are internal:

Device(GPI0) {
        Name(_HID, "MLNXBF33")
        Name(_UID, Zero)
        Name(_CCA, 1)
        Name(_CRS, ResourceTemplate() {
          // for fw_gpio[0] yu block
         Memory32Fixed(ReadWrite, 0x13401100, 0x00000080)
         // for yu_gpio_causereg0 block
         Memory32Fixed(ReadWrite, 0x13401c00, 0x00000020)
         Interrupt(ResourceConsumer, Edge, ActiveHigh, Shared)
           { BF_RSH0_YU }
       })
       Name(_DSD, Package() {
         ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
         Package() {
           Package () { "ngpios", 32 }, // Number of GPIO pins on gpio block 0
           Package () { "gpio-reserved-ranges", Package () {5, 1, 7, 3, 11, 31}},
         }
       })
     }
 Device(GPI1) {
       Name(_HID, "MLNXBF33")
       Name(_UID, 1)
       Name(_CCA, 1)
       Name(_CRS, ResourceTemplate() {
         // for fw_gpio[1] yu block
         Memory32Fixed(ReadWrite, 0x13401180, 0x00000080)
         // for yu_gpio_causereg1 block
         Memory32Fixed(ReadWrite, 0x13401c20, 0x00000020)
       })
       Name(_DSD, Package() {
         ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
         Package() {
           Package () { "ngpios", 24 }, // Number of GPIO pins on gpio block 1
           Package () { "gpio-reserved-ranges", Package () {0, 21}},
         }
       })
  }

    Device(PIN0) {
      Name(_HID, "MLNXBF34")
      Name(_UID, Zero)
      Name(_CCA, 1)
      Name(_CRS, ResourceTemplate() {
        // for fw_gpio[0] and fw_gpio[1] yu blocks
        Memory32Fixed(ReadWrite, 0x13401100, 0x00000100)
      })
     }

> 
> > Gpiochip_add_data_with_keys only reads the ngpios property if (ngpios
> > == 0) which is not the case when bgpio_init is called. bgpio_init uses "sz"
> argument to populate the ngpio in bgpio_init, which is not what we want.
> 
> Maybe bgpio_init() is not a good API for your case?


At the moment, bgpio_init handles all the direction in/out get/set gpio value for us.
So I can either remove bgpio_init so that we get the correct ngpios property, but will have to define get_gpio, set_gpio, dir in and dir out.
Or I can keep bgpio_init and device_property_read_u32 in the gpio-mlxbf3.c driver.
Please let me know which approach you prefer.
Andy Shevchenko Feb. 24, 2023, 3:12 p.m. UTC | #10
On Fri, Feb 24, 2023 at 4:42 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:
>
> > > > > > > Ah that’s my bad. The property should be called "ngpios" like
> > > > > > > in the DT
> > > > > > documentation. Will fix.
> > > > > >
> > > > > > And why do you need it? What's a corner case that the GPIO
> > > > > > library doesn't handle yet?
> > > > >
> > > > > We have 2 gpiochips, gpiochip 0 supports 32 gpio pins and gpiochip
> > > > > 1
> > > > supports only 24 pins.
> > > > > If I remove the logic from gpio-mlxbf3.c, the gpiolib.c logic will
> > > > > correctly set
> > > > the ngpios = 32 for gpiochip 0 but will wrongly set ngpios=32 for gpiogchip
> > 1:
> > > >
> > > > So, either you need to have two entries in DT per chip or ngpios should be
> > 56.
> > > >
> > > I already have 2 entries in my ACPI table, in the first entry, ngpios = 32 and
> > in the second entry ngpios = 24.
> >
> > Can you show the DSDT excerpt of this device? (Also including the pieces for
> > pin control)
>
> Our ACPI tables are internal:
>
> Device(GPI0) {
>         Name(_HID, "MLNXBF33")
>         Name(_UID, Zero)
>         Name(_CCA, 1)
>         Name(_CRS, ResourceTemplate() {
>           // for fw_gpio[0] yu block
>          Memory32Fixed(ReadWrite, 0x13401100, 0x00000080)
>          // for yu_gpio_causereg0 block
>          Memory32Fixed(ReadWrite, 0x13401c00, 0x00000020)
>          Interrupt(ResourceConsumer, Edge, ActiveHigh, Shared)
>            { BF_RSH0_YU }
>        })
>        Name(_DSD, Package() {
>          ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>          Package() {
>            Package () { "ngpios", 32 }, // Number of GPIO pins on gpio block 0
>            Package () { "gpio-reserved-ranges", Package () {5, 1, 7, 3, 11, 31}},
>          }
>        })
>      }
>  Device(GPI1) {
>        Name(_HID, "MLNXBF33")
>        Name(_UID, 1)
>        Name(_CCA, 1)
>        Name(_CRS, ResourceTemplate() {
>          // for fw_gpio[1] yu block
>          Memory32Fixed(ReadWrite, 0x13401180, 0x00000080)
>          // for yu_gpio_causereg1 block
>          Memory32Fixed(ReadWrite, 0x13401c20, 0x00000020)
>        })
>        Name(_DSD, Package() {
>          ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
>          Package() {
>            Package () { "ngpios", 24 }, // Number of GPIO pins on gpio block 1
>            Package () { "gpio-reserved-ranges", Package () {0, 21}},
>          }
>        })
>   }
>
>     Device(PIN0) {
>       Name(_HID, "MLNXBF34")
>       Name(_UID, Zero)
>       Name(_CCA, 1)
>       Name(_CRS, ResourceTemplate() {
>         // for fw_gpio[0] and fw_gpio[1] yu blocks
>         Memory32Fixed(ReadWrite, 0x13401100, 0x00000100)
>       })
>      }

So far I see no issues with the tables. Thanks for sharing!

> > > Gpiochip_add_data_with_keys only reads the ngpios property if (ngpios
> > > == 0) which is not the case when bgpio_init is called. bgpio_init uses "sz"
> > argument to populate the ngpio in bgpio_init, which is not what we want.
> >
> > Maybe bgpio_init() is not a good API for your case?
>
> At the moment, bgpio_init handles all the direction in/out get/set gpio value for us.
> So I can either remove bgpio_init so that we get the correct ngpios property, but will have to define get_gpio, set_gpio, dir in and dir out.
> Or I can keep bgpio_init and device_property_read_u32 in the gpio-mlxbf3.c driver.

So far it seems the issue is in bgpio_init() that doesn't handle
ngpios properly. Maybe we need to fix this first?

Btw, have you considered using the gpio-regmap approach?
Andy Shevchenko Feb. 24, 2023, 3:13 p.m. UTC | #11
On Fri, Feb 24, 2023 at 4:42 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:

>            Package () { "gpio-reserved-ranges", Package () {5, 1, 7, 3, 11, 31}},

Side note, doesn't it the same to

           Package () { "gpio-reserved-ranges", Package () {5, 1, 7, 34}},

?
Andy Shevchenko Feb. 24, 2023, 3:14 p.m. UTC | #12
On Fri, Feb 24, 2023 at 5:13 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Fri, Feb 24, 2023 at 4:42 PM Asmaa Mnebhi <asmaa@nvidia.com> wrote:
>
> >            Package () { "gpio-reserved-ranges", Package () {5, 1, 7, 3, 11, 31}},
>
> Side note, doesn't it the same to
>
>            Package () { "gpio-reserved-ranges", Package () {5, 1, 7, 34}},
>
> ?

Ah, now I got it, the 10 is OK, while 7-9 and 11+ are not.

Sorry for the noise.
Asmaa Mnebhi Feb. 24, 2023, 3:59 p.m. UTC | #13
> > > > Gpiochip_add_data_with_keys only reads the ngpios property if
> > > > (ngpios == 0) which is not the case when bgpio_init is called. bgpio_init
> uses "sz"
> > > argument to populate the ngpio in bgpio_init, which is not what we want.
> > >
> > > Maybe bgpio_init() is not a good API for your case?
> >
> > At the moment, bgpio_init handles all the direction in/out get/set gpio value
> for us.
> > So I can either remove bgpio_init so that we get the correct ngpios
> property, but will have to define get_gpio, set_gpio, dir in and dir out.
> > Or I can keep bgpio_init and device_property_read_u32 in the gpio-
> mlxbf3.c driver.
> 
> So far it seems the issue is in bgpio_init() that doesn't handle ngpios properly.
> Maybe we need to fix this first?

Ok I will send a sperate patch shortly addressing this.

> Btw, have you considered using the gpio-regmap approach?

Thanks!  I see examples of drivers already using this (gpio-tn48m.c). Will take a look.