All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs
@ 2021-09-21 22:29 Joey Gouly
  2021-09-21 22:29 ` [PATCH v1 1/1] pinctrl: add " Joey Gouly
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Joey Gouly @ 2021-09-21 22:29 UTC (permalink / raw)
  To: linux-gpio
  Cc: Linus Walleij, Hector Martin, Marc Zyngier, Alyssa Rosenzweig,
	Sven Peter, nd, Joey Gouly

Hi all,

This is a driver for the combined pinctrl / GPIO hw in the Apple M1 computers.
The driver is based on Corellium's driver [1], and has been rebased and cleaned up.
The bindings are in Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml

This has been tested with out-of-tree patches for the keyboard on the Macbook
Air, it has also been tested with i2c for the USB PD driver and PCIe (all
out-of-tree drivers currently).

I left two defines at the top 'USE_PINMUX_GENERIC_FN' and
'USE_PINCTRL_GENERIC_FN', I wasn't sure if I should use the generic functions for
getting the groups/functions, so I left both approaches in and will remove one
of them for the next version! Which approach should I use?

There is a branch here with the driver:
  https://gitlab.arm.com/linux-arm/jg-open/-/commits/pinctrl_apple_v1

There is also a branch which contains all the commits as I was
developing here (and keyboard drivers):
  https://gitlab.arm.com/linux-arm/jg-open/-/commits/m1-keyboard

I look forward to feedback!

Thanks,
Joey

note: I'm sending this from my arm work e-mail address, however it was done on
personal time.

note2: For those that have been testing this with PCIe etc, you will probably
want to also include the last commit in the following branch, as I dropped the
clock references in the code (due to the switch to power domains):
https://gitlab.arm.com/linux-arm/jg-open/-/commits/pinctrl_apple_v1_clock

[1]
https://github.com/corellium/linux-m1/blob/d5ec2a737e64de23a21025f9eddc554588deb23f/drivers/pinctrl/pinctrl-apple-gpio.c

Stan Skowronek (1):
  pinctrl: add pinctrl/GPIO driver for Apple SoCs

 MAINTAINERS                          |   1 +
 drivers/pinctrl/Kconfig              |  13 +
 drivers/pinctrl/Makefile             |   1 +
 drivers/pinctrl/pinctrl-apple-gpio.c | 652 +++++++++++++++++++++++++++
 4 files changed, 667 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-apple-gpio.c

-- 
2.17.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-21 22:29 [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs Joey Gouly
@ 2021-09-21 22:29 ` Joey Gouly
  2021-09-22  7:20   ` Andy Shevchenko
  2021-09-22 13:09   ` Marc Zyngier
  2021-09-22  6:59 ` [PATCH v1 0/1] " Andy Shevchenko
  2021-09-23  0:10 ` Linus Walleij
  2 siblings, 2 replies; 24+ messages in thread
From: Joey Gouly @ 2021-09-21 22:29 UTC (permalink / raw)
  To: linux-gpio
  Cc: Linus Walleij, Hector Martin, Marc Zyngier, Alyssa Rosenzweig,
	Sven Peter, nd, Stan Skowronek, Joey Gouly

From: Stan Skowronek <stan@corellium.com>

This driver adds support for the pinctrl / GPIO hardware found
on some Apple SoCs.

Co-authored-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Stan Skowronek <stan@corellium.com>
Signed-off-by: Joey Gouly <joey.gouly@arm.com>
---
 MAINTAINERS                          |   1 +
 drivers/pinctrl/Kconfig              |  13 +
 drivers/pinctrl/Makefile             |   1 +
 drivers/pinctrl/pinctrl-apple-gpio.c | 652 +++++++++++++++++++++++++++
 4 files changed, 667 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-apple-gpio.c

diff --git a/MAINTAINERS b/MAINTAINERS
index ca6d6fde85cf..e83e992b8ada 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1722,6 +1722,7 @@ F:	Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
 F:	Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
 F:	arch/arm64/boot/dts/apple/
 F:	drivers/irqchip/irq-apple-aic.c
+F:	drivers/pinctrl/pinctrl-apple-gpio.c
 F:	include/dt-bindings/interrupt-controller/apple-aic.h
 F:	include/dt-bindings/pinctrl/apple.h
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 31921108e456..7269614c85a1 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -31,6 +31,19 @@ config DEBUG_PINCTRL
 	help
 	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINCTRL_APPLE_GPIO
+	bool "Apple SoC GPIO pin controller driver"
+	depends on ARCH_APPLE
+	select PINMUX
+	select GPIOLIB
+	select GPIOLIB_IRQCHIP
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	select OF_GPIO
+	help
+	  This is the driver for the GPIO controller found on Apple ARM SoCs,
+	  including M1.
+
 config PINCTRL_ARTPEC6
 	bool "Axis ARTPEC-6 pin controller driver"
 	depends on MACH_ARTPEC6
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 200073bcc2c1..5e63de2ffcf4 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINMUX)		+= pinmux.o
 obj-$(CONFIG_PINCONF)		+= pinconf.o
 obj-$(CONFIG_OF)		+= devicetree.o
 obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
+obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o
 obj-$(CONFIG_PINCTRL_ARTPEC6)	+= pinctrl-artpec6.o
 obj-$(CONFIG_PINCTRL_AS3722)	+= pinctrl-as3722.o
 obj-$(CONFIG_PINCTRL_AXP209)	+= pinctrl-axp209.o
diff --git a/drivers/pinctrl/pinctrl-apple-gpio.c b/drivers/pinctrl/pinctrl-apple-gpio.c
new file mode 100644
index 000000000000..a27d21682f3a
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-apple-gpio.c
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Apple SoC pinctrl+GPIO+external IRQ driver
+ *
+ * Copyright (C) 2021 The Asahi Linux Contributors
+ * Copyright (C) 2020 Corellium LLC
+ *
+ * Based on: pinctrl-pistachio.c
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ * Copyright (C) 2014 Google, Inc.
+ */
+
+#define USE_PINMUX_GENERIC_FN 1
+#define USE_PINCTRL_GENERIC_FN 1
+
+#include <dt-bindings/pinctrl/apple.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-utils.h"
+#include "core.h"
+#include "pinmux.h"
+
+struct apple_gpio_pincfg {
+	uint8_t irqtype;
+	uint8_t stat;
+};
+
+#define PINCFG_STAT_OUTVAL	0x01
+#define PINCFG_STAT_OUTEN	0x02
+#define PINCFG_STAT_PERIPH	0x20
+#define PINCFG_STAT_IRQEN	0x80
+
+struct apple_gpio_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctldev;
+
+	unsigned int npins;
+	struct pinctrl_pin_desc *pins;
+	struct apple_gpio_pincfg *pin_cfgs;
+	const char **pin_names;
+	unsigned *pin_nums;
+
+	void __iomem *base;
+	unsigned int nirqgrps;
+
+	struct pinctrl_desc pinctrl_desc;
+	struct gpio_chip gpio_chip;
+	struct irq_chip irq_chip;
+};
+
+#define REG_GPIO(x)		(4 * (x))
+#define  REG_GPIOx_DATA		BIT(0)
+#define  REG_GPIOx_MODE_MASK	GENMASK(3, 1)
+#define REG_GPIOx_OUT	(1 << REG_GPIOx_DATA)
+#define REG_GPIOx_IN_IRQ_HI	(2 << REG_GPIOx_DATA)
+#define REG_GPIOx_IN_IRQ_LO	(3 << REG_GPIOx_DATA)
+#define REG_GPIOx_IN_IRQ_UP	(4 << REG_GPIOx_DATA)
+#define REG_GPIOx_IN_IRQ_DN	(5 << REG_GPIOx_DATA)
+#define REG_GPIOx_IN_IRQ_ANY	(6 << REG_GPIOx_DATA)
+#define REG_GPIOx_IN_IRQ_OFF	(7 << REG_GPIOx_DATA)
+#define  REG_GPIOx_PERIPH	BIT(5)
+#define  REG_GPIOx_CFG_DONE	BIT(9)
+#define  REG_GPIOx_GRP_MASK	GENMASK(18, 16)
+#define REG_IRQ(g,x)		(0x800 + 0x40 * (g) + 4 * ((x) >> 5))
+
+static void apple_gpio_set_reg(struct apple_gpio_pinctrl *pctl, unsigned pin, uint32_t clr, uint32_t set)
+{
+	void __iomem *ppin = pctl->base + pin * 4;
+	uint32_t prev, cfg;
+
+	prev = readl(ppin);
+	cfg = (prev & ~clr) | set;
+
+	if(!(prev & REG_GPIOx_CFG_DONE))
+		writel(cfg & ~REG_GPIOx_CFG_DONE, ppin);
+	writel(cfg, ppin);
+}
+
+static void apple_gpio_refresh_reg(struct apple_gpio_pinctrl *pctl, unsigned pin)
+{
+	struct apple_gpio_pincfg *pincfg = &pctl->pin_cfgs[pin];
+
+	int stat = pincfg->stat;
+	int outval = (stat & PINCFG_STAT_OUTVAL);
+
+	int clear = REG_GPIOx_MODE_MASK | REG_GPIOx_DATA;
+	int set = REG_GPIOx_CFG_DONE | outval;
+
+	if (stat & PINCFG_STAT_PERIPH) {
+		set |= REG_GPIOx_PERIPH;
+	} else {
+		clear |= REG_GPIOx_PERIPH;
+		if (stat & PINCFG_STAT_OUTEN)
+			set |= REG_GPIOx_OUT;
+		else if (stat & PINCFG_STAT_IRQEN)
+			set |= pincfg->irqtype;
+		else
+			set |= REG_GPIOx_IN_IRQ_OFF;
+	}
+
+	apple_gpio_set_reg(pctl, pin, clear, set);
+}
+
+static uint32_t apple_gpio_get_reg(struct apple_gpio_pinctrl *pctl, unsigned pin)
+{
+	return readl(pctl->base + pin * 4);
+}
+
+static void apple_gpio_init_reg(struct apple_gpio_pinctrl *pctl, unsigned pin)
+{
+	struct apple_gpio_pincfg *pincfg = &pctl->pin_cfgs[pin];
+	uint32_t reg = apple_gpio_get_reg(pctl, pin);
+
+	pincfg->irqtype = 0;
+	if(reg & REG_GPIOx_PERIPH) {
+		pincfg->stat = PINCFG_STAT_PERIPH;
+	} else if((reg & REG_GPIOx_MODE_MASK) == REG_GPIOx_OUT) {
+		pincfg->stat = PINCFG_STAT_OUTEN | (reg & PINCFG_STAT_OUTVAL);
+	} else if((reg & REG_GPIOx_MODE_MASK) == REG_GPIOx_IN_IRQ_OFF || !(reg & REG_GPIOx_MODE_MASK)) {
+		pincfg->stat = 0;
+	} else {
+		pincfg->irqtype = reg & REG_GPIOx_MODE_MASK;
+		pincfg->stat = PINCFG_STAT_IRQEN;
+	}
+}
+
+/* Pin controller functions */
+
+#if !USE_PINCTRL_GENERIC_FN
+static int apple_gpio_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct apple_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->npins;
+}
+
+static const char *apple_gpio_pinctrl_get_group_name(struct pinctrl_dev *pctldev, unsigned group)
+{
+	struct apple_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->pins[group].name;
+}
+
+static int apple_gpio_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, const unsigned **pins, unsigned *num_pins)
+{
+	struct apple_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = &pctl->pin_nums[group];
+	*num_pins = 1;
+
+	return 0;
+}
+#endif
+
+#if !USE_PINMUX_GENERIC_FN
+static const char *apple_gpio_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned func);
+static int apple_gpio_pinmux_get_functions_count(struct pinctrl_dev *pctldev);
+#endif
+
+static int apple_gpio_dt_node_to_map(struct pinctrl_dev *pctldev,
+				 struct device_node *np_config,
+				 struct pinctrl_map **map, unsigned *num_maps)
+{
+	unsigned reserved_maps;
+	struct apple_gpio_pinctrl *pctl;
+	u32 pinfunc, pin, func;
+	int num_pins, i;
+	const char* group_name;
+	const char* function_name;
+	struct device_node *node = np_config;
+	int ret = 0;
+
+	*map = NULL;
+	*num_maps = 0;
+	reserved_maps = 0;
+
+	pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	ret = of_property_count_u32_elems(node, "pinmux");
+	if (ret <= 0) {
+		dev_err(pctl->dev, "missing or empty pinmux property in node %pOFn.\n", node);
+		return -EINVAL;
+	}
+
+	num_pins = ret;
+
+	ret = pinctrl_utils_reserve_map(pctldev, map,
+			&reserved_maps, num_maps, num_pins);
+	if (ret) {
+		return ret;
+	}
+
+	for (i = 0; i < num_pins; i++) {
+		ret = of_property_read_u32_index(node, "pinmux",
+				i, &pinfunc);
+		if (ret) {
+			goto free_map;
+		}
+
+		pin = APPLE_PIN(pinfunc);
+		func = APPLE_FUNC(pinfunc);
+
+#if USE_PINMUX_GENERIC_FN
+		if (func >=pinmux_generic_get_function_count(pctldev)) {
+#else
+		if (func >= apple_gpio_pinmux_get_functions_count(pctldev)) {
+#endif
+			ret = -EINVAL;
+			goto free_map;
+		}
+
+#if USE_PINCTRL_GENERIC_FN
+		group_name = pinctrl_generic_get_group_name(pctldev, pin);
+#else
+		group_name = apple_gpio_pinctrl_get_group_name(pctldev, pin);
+#endif
+
+#if USE_PINMUX_GENERIC_FN
+		function_name = pinmux_generic_get_function_name(pctl->pctldev, func);
+#else
+		function_name = apple_gpio_pinmux_get_function_name(pctl->pctldev, func);
+#endif
+
+		ret = pinctrl_utils_add_map_mux(pctl->pctldev, map, &reserved_maps, num_maps,
+				group_name, function_name);
+		if (ret) {
+			goto free_map;
+		}
+	}
+
+free_map:
+	if (ret < 0) {
+		pinctrl_utils_free_map(pctldev, *map, *num_maps);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct pinctrl_ops apple_gpio_pinctrl_ops = {
+#if USE_PINCTRL_GENERIC_FN
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+#else
+	.get_groups_count = apple_gpio_pinctrl_get_groups_count,
+	.get_group_name = apple_gpio_pinctrl_get_group_name,
+	.get_group_pins = apple_gpio_pinctrl_get_group_pins,
+#endif
+	.dt_node_to_map = apple_gpio_dt_node_to_map,
+	.dt_free_map = pinctrl_utils_free_map,
+};
+
+/* Pin multiplexer functions */
+
+#if !USE_PINMUX_GENERIC_FN
+static int apple_gpio_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	return 2;
+}
+
+static const char *apple_gpio_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned func)
+{
+	return func ? "periph" : "gpio";
+}
+
+static int apple_gpio_pinmux_get_function_groups(struct pinctrl_dev *pctldev, unsigned func, const char * const **groups, unsigned * const num_groups)
+{
+	struct apple_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pctl->pin_names;
+	*num_groups = pctl->npins;
+	return 0;
+}
+#endif
+
+static int apple_gpio_pinmux_enable(struct pinctrl_dev *pctldev, unsigned func, unsigned group)
+{
+	struct apple_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	if(func)
+		pctl->pin_cfgs[group].stat |= PINCFG_STAT_PERIPH;
+	else
+		pctl->pin_cfgs[group].stat &= ~PINCFG_STAT_PERIPH;
+	apple_gpio_refresh_reg(pctl, group);
+
+	return 0;
+}
+
+static const struct pinmux_ops apple_gpio_pinmux_ops = {
+#if USE_PINMUX_GENERIC_FN
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+#else
+	.get_functions_count = apple_gpio_pinmux_get_functions_count,
+	.get_function_name = apple_gpio_pinmux_get_function_name,
+	.get_function_groups = apple_gpio_pinmux_get_function_groups,
+#endif
+	.set_mux = apple_gpio_pinmux_enable,
+	.strict = true,
+};
+
+/* GPIO chip functions */
+
+static int apple_gpio_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
+
+	return !(pctl->pin_cfgs[offset].stat & PINCFG_STAT_OUTEN) ?
+			GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
+}
+
+static int apple_gpio_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
+	uint32_t reg;
+
+	reg = apple_gpio_get_reg(pctl, offset);
+	return !!(reg & REG_GPIOx_DATA);
+}
+
+static void apple_gpio_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
+
+	if(value)
+		pctl->pin_cfgs[offset].stat |= PINCFG_STAT_OUTVAL;
+	else
+		pctl->pin_cfgs[offset].stat &= ~PINCFG_STAT_OUTVAL;
+	apple_gpio_refresh_reg(pctl, offset);
+}
+
+static int apple_gpio_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
+
+	pctl->pin_cfgs[offset].stat &= ~PINCFG_STAT_OUTEN;
+	apple_gpio_refresh_reg(pctl, offset);
+	return 0;
+}
+
+static int apple_gpio_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
+
+	int clear = PINCFG_STAT_PERIPH;
+	int set = PINCFG_STAT_OUTEN;
+
+	if (value)
+		set |= PINCFG_STAT_OUTVAL;
+	else
+		clear |= PINCFG_STAT_OUTVAL;
+
+	pctl->pin_cfgs[offset].stat &= ~clear;
+	pctl->pin_cfgs[offset].stat |= set;
+
+	apple_gpio_refresh_reg(pctl, offset);
+	return 0;
+}
+
+/* IRQ chip functions */
+
+static void apple_gpio_gpio_irq_ack(struct irq_data *data)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
+	unsigned irqgrp = FIELD_GET(REG_GPIOx_GRP_MASK, apple_gpio_get_reg(pctl, data->hwirq));
+
+	writel(1u << (data->hwirq & 31), pctl->base + REG_IRQ(irqgrp, data->hwirq));
+}
+
+static void apple_gpio_gpio_irq_mask(struct irq_data *data)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
+
+	pctl->pin_cfgs[data->hwirq].stat &= ~PINCFG_STAT_IRQEN;
+	apple_gpio_refresh_reg(pctl, data->hwirq);
+}
+
+static void apple_gpio_gpio_irq_unmask(struct irq_data *data)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
+
+	pctl->pin_cfgs[data->hwirq].stat |= PINCFG_STAT_IRQEN;
+	apple_gpio_refresh_reg(pctl, data->hwirq);
+}
+
+static unsigned int apple_gpio_gpio_irq_startup(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
+	unsigned irqgrp = 0;
+
+	apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_GRP_MASK, FIELD_PREP(REG_GPIOx_GRP_MASK, irqgrp));
+
+	apple_gpio_gpio_direction_input(chip, data->hwirq);
+	apple_gpio_gpio_irq_unmask(data);
+
+	return 0;
+}
+
+static int apple_gpio_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
+
+	switch(type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_RISING:
+		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_UP;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_DN;
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_ANY;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_HI;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_LO;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	apple_gpio_refresh_reg(pctl, data->hwirq);
+
+	if(type & IRQ_TYPE_LEVEL_MASK)
+		irq_set_handler_locked(data, handle_level_irq);
+	else
+		irq_set_handler_locked(data, handle_edge_irq);
+	return 0;
+}
+
+static void apple_gpio_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(gc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned irqgrp, pinh, pinl;
+	unsigned long pending;
+	unsigned int parent = irq_desc_get_irq(desc);
+
+	for (irqgrp = 0; irqgrp < pctl->nirqgrps; ++irqgrp) {
+		if (parent == gc->irq.parents[irqgrp])
+			break;
+	}
+
+	WARN_ON(irqgrp == pctl->nirqgrps);
+
+	chained_irq_enter(chip, desc);
+	for(pinh=0; pinh<pctl->npins; pinh+=32) {
+		pending = readl(pctl->base + REG_IRQ(irqgrp, pinh));
+		for_each_set_bit(pinl, &pending, 32)
+			generic_handle_irq(irq_linear_revmap(gc->irq.domain, pinh + pinl));
+	}
+	chained_irq_exit(chip, desc);
+}
+
+/* Probe & register */
+
+static int apple_gpio_gpio_register(struct apple_gpio_pinctrl *pctl)
+{
+	struct device_node *node = pctl->dev->of_node;
+	struct gpio_irq_chip *girq;
+	int i, ret = 0;
+
+	if(!of_find_property(node, "gpio-controller", NULL)) {
+		dev_err(pctl->dev, "Apple GPIO must have 'gpio-controller' property.\n");
+		return -ENODEV;
+	}
+
+	pctl->gpio_chip.label = dev_name(pctl->dev);
+	pctl->gpio_chip.request = gpiochip_generic_request;
+	pctl->gpio_chip.free = gpiochip_generic_free;
+	pctl->gpio_chip.get_direction = apple_gpio_gpio_get_direction;
+	pctl->gpio_chip.direction_input = apple_gpio_gpio_direction_input;
+	pctl->gpio_chip.direction_output = apple_gpio_gpio_direction_output;
+	pctl->gpio_chip.get = apple_gpio_gpio_get;
+	pctl->gpio_chip.set = apple_gpio_gpio_set;
+	pctl->gpio_chip.base = -1;
+	pctl->gpio_chip.ngpio = pctl->npins;
+	pctl->gpio_chip.parent = pctl->dev;
+	pctl->gpio_chip.of_node = node;
+
+	if (of_find_property(node, "interrupt-controller", NULL)) {
+		ret = platform_irq_count(to_platform_device(pctl->dev));
+		if(ret < 0)
+			return ret;
+
+		pctl->nirqgrps = ret;
+
+		pctl->irq_chip.name = dev_name(pctl->dev);
+		pctl->irq_chip.irq_startup = apple_gpio_gpio_irq_startup;
+		pctl->irq_chip.irq_ack = apple_gpio_gpio_irq_ack;
+		pctl->irq_chip.irq_mask = apple_gpio_gpio_irq_mask;
+		pctl->irq_chip.irq_unmask = apple_gpio_gpio_irq_unmask;
+		pctl->irq_chip.irq_set_type = apple_gpio_gpio_irq_set_type;
+
+		girq = &pctl->gpio_chip.irq;
+		girq->chip = &pctl->irq_chip;
+		girq->parent_handler = apple_gpio_gpio_irq_handler;
+		girq->num_parents = pctl->nirqgrps;
+
+		girq->parents = devm_kmalloc_array(pctl->dev, pctl->nirqgrps,
+			sizeof(girq->parents[0]), GFP_KERNEL);
+		if (!girq->parents)
+			return -ENOMEM;
+
+		for(i = 0; i < pctl->nirqgrps; i++) {
+			ret = platform_get_irq(to_platform_device(pctl->dev), i);
+			if(ret < 0) {
+				if(ret != -EPROBE_DEFER)
+					dev_err(pctl->dev, "Failed to map IRQ %d (%d).\n", i, ret);
+				return ret;
+			}
+			girq->parents[i] = ret;
+		}
+
+		girq->default_type = IRQ_TYPE_NONE;
+		girq->handler = handle_level_irq;
+	}
+
+	ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
+	if(ret < 0) {
+		dev_err(pctl->dev, "Failed to add GPIO chip (%d).\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id apple_gpio_pinctrl_of_match[] = {
+	{ .compatible = "apple,t8103-pinctrl", },
+	{ },
+};
+
+static int apple_gpio_pinctrl_probe(struct platform_device *pdev)
+{
+	struct apple_gpio_pinctrl *pctl;
+	struct of_phandle_args pinspec;
+	int res;
+	unsigned pin_base, i;
+
+	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+	if(!pctl)
+		return -ENOMEM;
+	pctl->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, pctl);
+
+	if (of_parse_phandle_with_fixed_args(pdev->dev.of_node, "gpio-ranges",
+			3, 0, &pinspec)) {
+		dev_err(&pdev->dev, "gpio-ranges property not found\n");
+		return -EINVAL;
+	}
+
+	pctl->npins = pinspec.args[2];
+	pin_base = pinspec.args[1];
+
+	pctl->pins = devm_kmalloc_array(&pdev->dev, pctl->npins, sizeof(pctl->pins[0]), GFP_KERNEL);
+	if(!pctl->pins)
+		return -ENOMEM;
+	pctl->pin_names = devm_kmalloc_array(&pdev->dev, pctl->npins, sizeof(pctl->pin_names[0]), GFP_KERNEL);
+	if(!pctl->pin_names)
+		return -ENOMEM;
+	pctl->pin_nums = devm_kmalloc_array(&pdev->dev, pctl->npins, sizeof(pctl->pin_nums[0]), GFP_KERNEL);
+	if(!pctl->pin_nums)
+		return -ENOMEM;
+	pctl->pin_cfgs = devm_kmalloc_array(&pdev->dev, pctl->npins, sizeof(pctl->pin_cfgs[0]), GFP_KERNEL);
+	if(!pctl->pin_cfgs)
+		return -ENOMEM;
+
+	pctl->base = devm_platform_ioremap_resource(pdev, 0);
+	if(IS_ERR(pctl->base))
+		return PTR_ERR(pctl->base);
+
+	for(i=0; i<pctl->npins; i++) {
+		apple_gpio_init_reg(pctl, i);
+
+		pctl->pins[i].number = i + pin_base;
+		pctl->pins[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "PIN%u", i + pin_base);
+		pctl->pins[i].drv_data = pctl;
+		pctl->pin_names[i] = pctl->pins[i].name;
+		pctl->pin_nums[i] = i + pin_base;
+	}
+
+	pctl->pinctrl_desc.name = dev_name(pctl->dev);
+	pctl->pinctrl_desc.pins = pctl->pins;
+	pctl->pinctrl_desc.npins = pctl->npins;
+	pctl->pinctrl_desc.pctlops = &apple_gpio_pinctrl_ops;
+	pctl->pinctrl_desc.pmxops = &apple_gpio_pinmux_ops;
+
+	pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->pinctrl_desc, pctl);
+	if (IS_ERR(pctl->pctldev)) {
+		dev_err(&pdev->dev, "Failed to register pinctrl device.\n");
+		return PTR_ERR(pctl->pctldev);
+	}
+
+#if USE_PINCTRL_GENERIC_FN
+	for (i = 0; i < pctl->npins; i++) {
+		res = pinctrl_generic_add_group(pctl->pctldev, pctl->pins[i].name,
+						pctl->pin_nums + i, 1, pctl);
+		if (res < 0) {
+			dev_err(pctl->dev, "Failed to register group.");
+			return res;
+		}
+	}
+#endif
+
+#if USE_PINMUX_GENERIC_FN
+	res = pinmux_generic_add_function(pctl->pctldev, "gpio", pctl->pin_names, pctl->npins, pctl);
+
+	if (res < 0) {
+		dev_err(pctl->dev, "Failed to register function.");
+		return res;
+	}
+
+	res = pinmux_generic_add_function(pctl->pctldev, "periph", pctl->pin_names, pctl->npins, pctl);
+
+	if (res < 0) {
+		dev_err(pctl->dev, "Failed to register function.");
+		return res;
+	}
+#endif
+
+	return apple_gpio_gpio_register(pctl);
+}
+
+static struct platform_driver apple_gpio_pinctrl_driver = {
+	.driver = {
+		.name = "apple-gpio-pinctrl",
+		.of_match_table = apple_gpio_pinctrl_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = apple_gpio_pinctrl_probe,
+};
+
+module_platform_driver(apple_gpio_pinctrl_driver);
+
+MODULE_DESCRIPTION("Apple pinctrl/GPIO driver");
+MODULE_AUTHOR("Stan Skowronek <stan@corellium.com>");
+MODULE_AUTHOR("Joey Gouly <joey.gouly@arm.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs
  2021-09-21 22:29 [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs Joey Gouly
  2021-09-21 22:29 ` [PATCH v1 1/1] pinctrl: add " Joey Gouly
@ 2021-09-22  6:59 ` Andy Shevchenko
  2021-09-23  0:10 ` Linus Walleij
  2 siblings, 0 replies; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-22  6:59 UTC (permalink / raw)
  To: Joey Gouly
  Cc: linux-gpio, Linus Walleij, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, Sven Peter, nd

On Tue, Sep 21, 2021 at 11:29:55PM +0100, Joey Gouly wrote:
> Hi all,
> 
> This is a driver for the combined pinctrl / GPIO hw in the Apple M1 computers.
> The driver is based on Corellium's driver [1], and has been rebased and cleaned up.
> The bindings are in Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml

Have you checked if there is any (qualcomm / samsung / ?) existing driver is
close enough to this hardware?

> This has been tested with out-of-tree patches for the keyboard on the Macbook
> Air, it has also been tested with i2c for the USB PD driver and PCIe (all
> out-of-tree drivers currently).
> 
> I left two defines at the top 'USE_PINMUX_GENERIC_FN' and
> 'USE_PINCTRL_GENERIC_FN', I wasn't sure if I should use the generic functions for
> getting the groups/functions, so I left both approaches in and will remove one
> of them for the next version! Which approach should I use?

Try to get rid of defines.

> There is a branch here with the driver:
>   https://gitlab.arm.com/linux-arm/jg-open/-/commits/pinctrl_apple_v1
> 
> There is also a branch which contains all the commits as I was
> developing here (and keyboard drivers):
>   https://gitlab.arm.com/linux-arm/jg-open/-/commits/m1-keyboard
> 
> I look forward to feedback!
> 
> Thanks,
> Joey
> 
> note: I'm sending this from my arm work e-mail address, however it was done on
> personal time.

It doesn't matter to the community. Check this with your employer.

> note2: For those that have been testing this with PCIe etc, you will probably
> want to also include the last commit in the following branch, as I dropped the
> clock references in the code (due to the switch to power domains):
> https://gitlab.arm.com/linux-arm/jg-open/-/commits/pinctrl_apple_v1_clock
> 
> [1]
> https://github.com/corellium/linux-m1/blob/d5ec2a737e64de23a21025f9eddc554588deb23f/drivers/pinctrl/pinctrl-apple-gpio.c

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-21 22:29 ` [PATCH v1 1/1] pinctrl: add " Joey Gouly
@ 2021-09-22  7:20   ` Andy Shevchenko
  2021-09-25 13:44     ` Joey Gouly
  2021-09-22 13:09   ` Marc Zyngier
  1 sibling, 1 reply; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-22  7:20 UTC (permalink / raw)
  To: Joey Gouly
  Cc: linux-gpio, Linus Walleij, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, Sven Peter, nd, Stan Skowronek

On Tue, Sep 21, 2021 at 11:29:56PM +0100, Joey Gouly wrote:
> From: Stan Skowronek <stan@corellium.com>
> 
> This driver adds support for the pinctrl / GPIO hardware found
> on some Apple SoCs.
> 
> Co-authored-by: Joey Gouly <joey.gouly@arm.com>

Have you read Submitting Patches document? Please read and act accordingly.

> Signed-off-by: Stan Skowronek <stan@corellium.com>
> Signed-off-by: Joey Gouly <joey.gouly@arm.com>

...

> +F:	drivers/pinctrl/pinctrl-apple-gpio.c

Are you sure it's a good naming? Have you guaranteed that next Apple silicons
will use the same / compatible IP?

...

> +config PINCTRL_APPLE_GPIO
> +	bool "Apple SoC GPIO pin controller driver"

Why not module?

> +	depends on ARCH_APPLE
> +	select PINMUX
> +	select GPIOLIB
> +	select GPIOLIB_IRQCHIP
> +	select GENERIC_PINCTRL_GROUPS
> +	select GENERIC_PINMUX_FUNCTIONS
> +	select OF_GPIO
> +	help
> +	  This is the driver for the GPIO controller found on Apple ARM SoCs,
> +	  including M1.

After fixing above, put a standard sentence on how the module will be called.

...

> +#define USE_PINMUX_GENERIC_FN 1
> +#define USE_PINCTRL_GENERIC_FN 1

Why you left them if they are hard coded?

...

> +#define PINCFG_STAT_OUTVAL	0x01
> +#define PINCFG_STAT_OUTEN	0x02
> +#define PINCFG_STAT_PERIPH	0x20
> +#define PINCFG_STAT_IRQEN	0x80

BIT() ?

...

> +	struct apple_gpio_pincfg *pin_cfgs;

Can you use the data structures from generic pin control?

...

> +#define REG_GPIOx_OUT	(1 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_HI	(2 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_LO	(3 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_UP	(4 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_DN	(5 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_ANY	(6 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_OFF	(7 << REG_GPIOx_DATA)

Easy to read and understand if the shift is a plain number.

..

> +	prev = readl(ppin);
> +	cfg = (prev & ~clr) | set;
> +
> +	if(!(prev & REG_GPIOx_CFG_DONE))
> +		writel(cfg & ~REG_GPIOx_CFG_DONE, ppin);
> +	writel(cfg, ppin);

Is it IP requirement to have sequential writes? Can it be done in one?

...

> +#if USE_PINMUX_GENERIC_FN
> +		if (func >=pinmux_generic_get_function_count(pctldev)) {

Missed space.
I noticed more places, so please carefully check the style.

> +#else
> +		if (func >= apple_gpio_pinmux_get_functions_count(pctldev)) {
> +#endif
> +			ret = -EINVAL;
> +			goto free_map;
> +		}

...

> +static int apple_gpio_pinmux_get_function_groups(struct pinctrl_dev *pctldev, unsigned func, const char * const **groups, unsigned * const num_groups)

Seems quite too long line.

...

> +	int i, ret = 0;

Don't hid ret assignment here. It's error prone.

...

> +	if(!of_find_property(node, "gpio-controller", NULL)) {
> +		dev_err(pctl->dev, "Apple GPIO must have 'gpio-controller' property.\n");
> +		return -ENODEV;
> +	}

How is it possible?

...

> +	if (of_find_property(node, "interrupt-controller", NULL)) {

Are you sure you need this check and OF core doesn't provide a generic way for this?

> +		ret = platform_irq_count(to_platform_device(pctl->dev));
> +		if(ret < 0)
> +			return ret;
> +
> +		pctl->nirqgrps = ret;
> +
> +		pctl->irq_chip.name = dev_name(pctl->dev);
> +		pctl->irq_chip.irq_startup = apple_gpio_gpio_irq_startup;
> +		pctl->irq_chip.irq_ack = apple_gpio_gpio_irq_ack;
> +		pctl->irq_chip.irq_mask = apple_gpio_gpio_irq_mask;
> +		pctl->irq_chip.irq_unmask = apple_gpio_gpio_irq_unmask;
> +		pctl->irq_chip.irq_set_type = apple_gpio_gpio_irq_set_type;
> +
> +		girq = &pctl->gpio_chip.irq;
> +		girq->chip = &pctl->irq_chip;
> +		girq->parent_handler = apple_gpio_gpio_irq_handler;
> +		girq->num_parents = pctl->nirqgrps;
> +
> +		girq->parents = devm_kmalloc_array(pctl->dev, pctl->nirqgrps,
> +			sizeof(girq->parents[0]), GFP_KERNEL);

sizeof(*...)

> +		if (!girq->parents)
> +			return -ENOMEM;
> +
> +		for(i = 0; i < pctl->nirqgrps; i++) {
> +			ret = platform_get_irq(to_platform_device(pctl->dev), i);
> +			if(ret < 0) {

> +				if(ret != -EPROBE_DEFER)
> +					dev_err(pctl->dev, "Failed to map IRQ %d (%d).\n", i, ret);
> +				return ret;

return dev_err_probe(...);

> +			}
> +			girq->parents[i] = ret;
> +		}
> +
> +		girq->default_type = IRQ_TYPE_NONE;
> +		girq->handler = handle_level_irq;
> +	}

...

> +	ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
> +	if(ret < 0) {
> +		dev_err(pctl->dev, "Failed to add GPIO chip (%d).\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;

Simple `return devm_gpiochip_add_data(...);` will do the job.

...

> +static const struct of_device_id apple_gpio_pinctrl_of_match[] = {
> +	{ .compatible = "apple,t8103-pinctrl", },

> +	{ },

No comma for the array termination.

> +};

...

> +	if (of_parse_phandle_with_fixed_args(pdev->dev.of_node, "gpio-ranges",
> +			3, 0, &pinspec)) {
> +		dev_err(&pdev->dev, "gpio-ranges property not found\n");
> +		return -EINVAL;
> +	}
> +
> +	pctl->npins = pinspec.args[2];
> +	pin_base = pinspec.args[1];


Isn't this being provided by pin control?

...

> +		pctl->pins[i].number = i + pin_base;
> +		pctl->pins[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "PIN%u", i + pin_base);
> +		pctl->pins[i].drv_data = pctl;
> +		pctl->pin_names[i] = pctl->pins[i].name;
> +		pctl->pin_nums[i] = i + pin_base;

Try to reduce Yoda style, i.e. use `pin_base + i`.

...

> +static struct platform_driver apple_gpio_pinctrl_driver = {
> +	.driver = {
> +		.name = "apple-gpio-pinctrl",
> +		.of_match_table = apple_gpio_pinctrl_of_match,
> +		.suppress_bind_attrs = true,
> +	},
> +	.probe = apple_gpio_pinctrl_probe,
> +};

> +

Redundant blank line.

> +module_platform_driver(apple_gpio_pinctrl_driver);

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-21 22:29 ` [PATCH v1 1/1] pinctrl: add " Joey Gouly
  2021-09-22  7:20   ` Andy Shevchenko
@ 2021-09-22 13:09   ` Marc Zyngier
  2021-09-22 23:58     ` Linus Walleij
  1 sibling, 1 reply; 24+ messages in thread
From: Marc Zyngier @ 2021-09-22 13:09 UTC (permalink / raw)
  To: Joey Gouly
  Cc: linux-gpio, Linus Walleij, Hector Martin, Alyssa Rosenzweig,
	Sven Peter, nd, Stan Skowronek

Hi Joey,

On Tue, 21 Sep 2021 23:29:56 +0100,
Joey Gouly <joey.gouly@arm.com> wrote:
> 
> From: Stan Skowronek <stan@corellium.com>
> 
> This driver adds support for the pinctrl / GPIO hardware found
> on some Apple SoCs.
> 
> Co-authored-by: Joey Gouly <joey.gouly@arm.com>
> Signed-off-by: Stan Skowronek <stan@corellium.com>
> Signed-off-by: Joey Gouly <joey.gouly@arm.com>
> ---
>  MAINTAINERS                          |   1 +
>  drivers/pinctrl/Kconfig              |  13 +
>  drivers/pinctrl/Makefile             |   1 +
>  drivers/pinctrl/pinctrl-apple-gpio.c | 652 +++++++++++++++++++++++++++
>  4 files changed, 667 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-apple-gpio.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ca6d6fde85cf..e83e992b8ada 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1722,6 +1722,7 @@ F:	Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
>  F:	Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
>  F:	arch/arm64/boot/dts/apple/
>  F:	drivers/irqchip/irq-apple-aic.c
> +F:	drivers/pinctrl/pinctrl-apple-gpio.c
>  F:	include/dt-bindings/interrupt-controller/apple-aic.h
>  F:	include/dt-bindings/pinctrl/apple.h
>  
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 31921108e456..7269614c85a1 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -31,6 +31,19 @@ config DEBUG_PINCTRL
>  	help
>  	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
>  
> +config PINCTRL_APPLE_GPIO
> +	bool "Apple SoC GPIO pin controller driver"
> +	depends on ARCH_APPLE
> +	select PINMUX
> +	select GPIOLIB
> +	select GPIOLIB_IRQCHIP
> +	select GENERIC_PINCTRL_GROUPS
> +	select GENERIC_PINMUX_FUNCTIONS
> +	select OF_GPIO
> +	help
> +	  This is the driver for the GPIO controller found on Apple ARM SoCs,
> +	  including M1.
> +
>  config PINCTRL_ARTPEC6
>  	bool "Axis ARTPEC-6 pin controller driver"
>  	depends on MACH_ARTPEC6
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index 200073bcc2c1..5e63de2ffcf4 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_PINMUX)		+= pinmux.o
>  obj-$(CONFIG_PINCONF)		+= pinconf.o
>  obj-$(CONFIG_OF)		+= devicetree.o
>  obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
> +obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o
>  obj-$(CONFIG_PINCTRL_ARTPEC6)	+= pinctrl-artpec6.o
>  obj-$(CONFIG_PINCTRL_AS3722)	+= pinctrl-as3722.o
>  obj-$(CONFIG_PINCTRL_AXP209)	+= pinctrl-axp209.o
> diff --git a/drivers/pinctrl/pinctrl-apple-gpio.c b/drivers/pinctrl/pinctrl-apple-gpio.c
> new file mode 100644
> index 000000000000..a27d21682f3a
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-apple-gpio.c
> @@ -0,0 +1,652 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Apple SoC pinctrl+GPIO+external IRQ driver
> + *
> + * Copyright (C) 2021 The Asahi Linux Contributors
> + * Copyright (C) 2020 Corellium LLC
> + *
> + * Based on: pinctrl-pistachio.c
> + * Copyright (C) 2014 Imagination Technologies Ltd.
> + * Copyright (C) 2014 Google, Inc.
> + */
> +
> +#define USE_PINMUX_GENERIC_FN 1
> +#define USE_PINCTRL_GENERIC_FN 1
> +
> +#include <dt-bindings/pinctrl/apple.h>
> +#include <linux/clk.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/platform_device.h>
> +
> +#include "pinctrl-utils.h"
> +#include "core.h"
> +#include "pinmux.h"
> +
> +struct apple_gpio_pincfg {
> +	uint8_t irqtype;
> +	uint8_t stat;
> +};
> +
> +#define PINCFG_STAT_OUTVAL	0x01
> +#define PINCFG_STAT_OUTEN	0x02
> +#define PINCFG_STAT_PERIPH	0x20
> +#define PINCFG_STAT_IRQEN	0x80
> +
> +struct apple_gpio_pinctrl {
> +	struct device *dev;
> +	struct pinctrl_dev *pctldev;
> +
> +	unsigned int npins;
> +	struct pinctrl_pin_desc *pins;
> +	struct apple_gpio_pincfg *pin_cfgs;
> +	const char **pin_names;
> +	unsigned *pin_nums;
> +
> +	void __iomem *base;
> +	unsigned int nirqgrps;
> +
> +	struct pinctrl_desc pinctrl_desc;
> +	struct gpio_chip gpio_chip;
> +	struct irq_chip irq_chip;
> +};
> +
> +#define REG_GPIO(x)		(4 * (x))
> +#define  REG_GPIOx_DATA		BIT(0)
> +#define  REG_GPIOx_MODE_MASK	GENMASK(3, 1)
> +#define REG_GPIOx_OUT	(1 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_HI	(2 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_LO	(3 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_UP	(4 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_DN	(5 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_ANY	(6 << REG_GPIOx_DATA)
> +#define REG_GPIOx_IN_IRQ_OFF	(7 << REG_GPIOx_DATA)
> +#define  REG_GPIOx_PERIPH	BIT(5)
> +#define  REG_GPIOx_CFG_DONE	BIT(9)
> +#define  REG_GPIOx_GRP_MASK	GENMASK(18, 16)
> +#define REG_IRQ(g,x)		(0x800 + 0x40 * (g) + 4 * ((x) >> 5))
> +
> +static void apple_gpio_set_reg(struct apple_gpio_pinctrl *pctl, unsigned pin, uint32_t clr, uint32_t set)
> +{
> +	void __iomem *ppin = pctl->base + pin * 4;
> +	uint32_t prev, cfg;
> +
> +	prev = readl(ppin);
> +	cfg = (prev & ~clr) | set;
> +
> +	if(!(prev & REG_GPIOx_CFG_DONE))
> +		writel(cfg & ~REG_GPIOx_CFG_DONE, ppin);
> +	writel(cfg, ppin);

I'll add my usual rant about the use of relaxed accessors, or lack
thereof. Unless there is a compelling reason for spitting out
barriers everywhere, please use the _relaxed version.

> +}
> +
> +static void apple_gpio_refresh_reg(struct apple_gpio_pinctrl *pctl, unsigned pin)
> +{
> +	struct apple_gpio_pincfg *pincfg = &pctl->pin_cfgs[pin];
> +
> +	int stat = pincfg->stat;
> +	int outval = (stat & PINCFG_STAT_OUTVAL);
> +
> +	int clear = REG_GPIOx_MODE_MASK | REG_GPIOx_DATA;
> +	int set = REG_GPIOx_CFG_DONE | outval;
> +
> +	if (stat & PINCFG_STAT_PERIPH) {
> +		set |= REG_GPIOx_PERIPH;
> +	} else {
> +		clear |= REG_GPIOx_PERIPH;
> +		if (stat & PINCFG_STAT_OUTEN)
> +			set |= REG_GPIOx_OUT;
> +		else if (stat & PINCFG_STAT_IRQEN)
> +			set |= pincfg->irqtype;
> +		else
> +			set |= REG_GPIOx_IN_IRQ_OFF;
> +	}
> +
> +	apple_gpio_set_reg(pctl, pin, clear, set);

Please add some documentation on how these bits behave. This is
specially important as the mask/unmask operations can be used
concurrently. Unless the HW ensures mutual exclusion one way or
another (such as separate registers per interrupts?), you'll need some
locking here.

[...]

I know nothing about pinctrl and GPIO, so I'll skip directly to my own
turf...

> +/* IRQ chip functions */
> +
> +static void apple_gpio_gpio_irq_ack(struct irq_data *data)
> +{
> +	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
> +	unsigned irqgrp = FIELD_GET(REG_GPIOx_GRP_MASK, apple_gpio_get_reg(pctl, data->hwirq));
> +
> +	writel(1u << (data->hwirq & 31), pctl->base + REG_IRQ(irqgrp, data->hwirq));

Use BIT().

> +}
> +
> +static void apple_gpio_gpio_irq_mask(struct irq_data *data)
> +{
> +	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
> +
> +	pctl->pin_cfgs[data->hwirq].stat &= ~PINCFG_STAT_IRQEN;
> +	apple_gpio_refresh_reg(pctl, data->hwirq);

See my above note about the potential requirement for locking.

> +}
> +
> +static void apple_gpio_gpio_irq_unmask(struct irq_data *data)
> +{
> +	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
> +
> +	pctl->pin_cfgs[data->hwirq].stat |= PINCFG_STAT_IRQEN;
> +	apple_gpio_refresh_reg(pctl, data->hwirq);
> +}
> +
> +static unsigned int apple_gpio_gpio_irq_startup(struct irq_data *data)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
> +	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
> +	unsigned irqgrp = 0;

Useless variable?

> +
> +	apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_GRP_MASK, FIELD_PREP(REG_GPIOx_GRP_MASK, irqgrp));
> +
> +	apple_gpio_gpio_direction_input(chip, data->hwirq);
> +	apple_gpio_gpio_irq_unmask(data);
> +
> +	return 0;
> +}
> +
> +static int apple_gpio_gpio_irq_set_type(struct irq_data *data, unsigned int type)
> +{
> +	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
> +
> +	switch(type & IRQ_TYPE_SENSE_MASK) {
> +	case IRQ_TYPE_EDGE_RISING:
> +		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_UP;
> +		break;
> +	case IRQ_TYPE_EDGE_FALLING:
> +		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_DN;
> +		break;
> +	case IRQ_TYPE_EDGE_BOTH:
> +		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_ANY;
> +		break;
> +	case IRQ_TYPE_LEVEL_HIGH:
> +		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_HI;
> +		break;
> +	case IRQ_TYPE_LEVEL_LOW:
> +		pctl->pin_cfgs[data->hwirq].irqtype = REG_GPIOx_IN_IRQ_LO;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	apple_gpio_refresh_reg(pctl, data->hwirq);

A general question about how the HW works: you seem to shadow some of
the state in memory, only to end-up committing it into the HW at a
later point. Why the indirection? I don't think a RMW operation is
going to hurt.

> +
> +	if(type & IRQ_TYPE_LEVEL_MASK)
> +		irq_set_handler_locked(data, handle_level_irq);
> +	else
> +		irq_set_handler_locked(data, handle_edge_irq);
> +	return 0;
> +}
> +
> +static void apple_gpio_gpio_irq_handler(struct irq_desc *desc)
> +{
> +	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
> +	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(gc);
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	unsigned irqgrp, pinh, pinl;
> +	unsigned long pending;
> +	unsigned int parent = irq_desc_get_irq(desc);
> +
> +	for (irqgrp = 0; irqgrp < pctl->nirqgrps; ++irqgrp) {
> +		if (parent == gc->irq.parents[irqgrp])
> +			break;
> +	}

This seems counter-productive. Why can't the handler data give you the
correct context without having to iterate on internal data structures?

> +
> +	WARN_ON(irqgrp == pctl->nirqgrps);

WARN_ON(), followed by the dereferencing of random data? If that
cannot happen, please drop it. If it can happen, just fix it. See
below for my take on this.

> +
> +	chained_irq_enter(chip, desc);
> +	for(pinh=0; pinh<pctl->npins; pinh+=32) {

Coding style, please (all over the file).

> +		pending = readl(pctl->base + REG_IRQ(irqgrp, pinh));
> +		for_each_set_bit(pinl, &pending, 32)
> +			generic_handle_irq(irq_linear_revmap(gc->irq.domain, pinh + pinl));

This should be a call to generic_handle_domain_irq().
irq_linear_revmap() is going away soon.

> +	}
> +	chained_irq_exit(chip, desc);
> +}
> +
> +/* Probe & register */
> +
> +static int apple_gpio_gpio_register(struct apple_gpio_pinctrl *pctl)
> +{
> +	struct device_node *node = pctl->dev->of_node;
> +	struct gpio_irq_chip *girq;
> +	int i, ret = 0;
> +
> +	if(!of_find_property(node, "gpio-controller", NULL)) {
> +		dev_err(pctl->dev, "Apple GPIO must have 'gpio-controller' property.\n");
> +		return -ENODEV;
> +	}
> +
> +	pctl->gpio_chip.label = dev_name(pctl->dev);
> +	pctl->gpio_chip.request = gpiochip_generic_request;
> +	pctl->gpio_chip.free = gpiochip_generic_free;
> +	pctl->gpio_chip.get_direction = apple_gpio_gpio_get_direction;
> +	pctl->gpio_chip.direction_input = apple_gpio_gpio_direction_input;
> +	pctl->gpio_chip.direction_output = apple_gpio_gpio_direction_output;
> +	pctl->gpio_chip.get = apple_gpio_gpio_get;
> +	pctl->gpio_chip.set = apple_gpio_gpio_set;
> +	pctl->gpio_chip.base = -1;
> +	pctl->gpio_chip.ngpio = pctl->npins;
> +	pctl->gpio_chip.parent = pctl->dev;
> +	pctl->gpio_chip.of_node = node;
> +
> +	if (of_find_property(node, "interrupt-controller", NULL)) {
> +		ret = platform_irq_count(to_platform_device(pctl->dev));
> +		if(ret < 0)
> +			return ret;
> +
> +		pctl->nirqgrps = ret;
> +
> +		pctl->irq_chip.name = dev_name(pctl->dev);

No, please. We don't need a massively long name that will make
/proc/interrupts more messy than it needs to be (and creates ABI
issues when someone repaints the DT). Just say "GPIO".

> +		pctl->irq_chip.irq_startup = apple_gpio_gpio_irq_startup;
> +		pctl->irq_chip.irq_ack = apple_gpio_gpio_irq_ack;
> +		pctl->irq_chip.irq_mask = apple_gpio_gpio_irq_mask;
> +		pctl->irq_chip.irq_unmask = apple_gpio_gpio_irq_unmask;
> +		pctl->irq_chip.irq_set_type = apple_gpio_gpio_irq_set_type;
> +
> +		girq = &pctl->gpio_chip.irq;
> +		girq->chip = &pctl->irq_chip;
> +		girq->parent_handler = apple_gpio_gpio_irq_handler;
> +		girq->num_parents = pctl->nirqgrps;
> +
> +		girq->parents = devm_kmalloc_array(pctl->dev, pctl->nirqgrps,
> +			sizeof(girq->parents[0]), GFP_KERNEL);
> +		if (!girq->parents)
> +			return -ENOMEM;
> +
> +		for(i = 0; i < pctl->nirqgrps; i++) {
> +			ret = platform_get_irq(to_platform_device(pctl->dev), i);
> +			if(ret < 0) {
> +				if(ret != -EPROBE_DEFER)
> +					dev_err(pctl->dev, "Failed to map IRQ %d (%d).\n", i, ret);
> +				return ret;
> +			}
> +			girq->parents[i] = ret;
> +		}

In general, keeping track of the parent interrupts in an interrupt
controller driver is a sure sign that things are badly organised.
Here, you have a single irqchip context that handles multiple muxes.
You really should have one context per mux, which would simplify your
interrupt handling.

An alternative is to use the fact that all the interrupts to the AIC
form a contiguous space, and use that to directly index into the array.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-22 13:09   ` Marc Zyngier
@ 2021-09-22 23:58     ` Linus Walleij
  0 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-09-22 23:58 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Joey Gouly, open list:GPIO SUBSYSTEM, Hector Martin,
	Alyssa Rosenzweig, Sven Peter, nd, Stan Skowronek

On Wed, Sep 22, 2021 at 3:09 PM Marc Zyngier <maz@kernel.org> wrote:
> Joey Gouly <joey.gouly@arm.com> wrote:

> > +             pctl->irq_chip.name = dev_name(pctl->dev);
>
> No, please. We don't need a massively long name that will make
> /proc/interrupts more messy than it needs to be (and creates ABI
> issues when someone repaints the DT). Just say "GPIO".

There may be some GPIO expanders in some systems as well
so I'd use "APPLE-GPIO" or similar so we know it is the one
on the SoC.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs
  2021-09-21 22:29 [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs Joey Gouly
  2021-09-21 22:29 ` [PATCH v1 1/1] pinctrl: add " Joey Gouly
  2021-09-22  6:59 ` [PATCH v1 0/1] " Andy Shevchenko
@ 2021-09-23  0:10 ` Linus Walleij
  2 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-09-23  0:10 UTC (permalink / raw)
  To: Joey Gouly
  Cc: open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, Sven Peter, nd

On Wed, Sep 22, 2021 at 12:30 AM Joey Gouly <joey.gouly@arm.com> wrote:

> I left two defines at the top 'USE_PINMUX_GENERIC_FN' and
> 'USE_PINCTRL_GENERIC_FN', I wasn't sure if I should use the generic functions for
> getting the groups/functions, so I left both approaches in and will remove one
> of them for the next version! Which approach should I use?

I think you should go with generic as far as possible, it usually
gives less code to maintain.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-22  7:20   ` Andy Shevchenko
@ 2021-09-25 13:44     ` Joey Gouly
  2021-09-26  5:08       ` Andy Shevchenko
  0 siblings, 1 reply; 24+ messages in thread
From: Joey Gouly @ 2021-09-25 13:44 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-gpio, Linus Walleij, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, Sven Peter, nd, Stan Skowronek

Hi Andy,

Thanks for the review!

On Wed, Sep 22, 2021 at 10:20:39AM +0300, Andy Shevchenko wrote:

[...]

> > +F:	drivers/pinctrl/pinctrl-apple-gpio.c
> 
> Are you sure it's a good naming? Have you guaranteed that next Apple silicons
> will use the same / compatible IP?
We don't know what will be in future Apple SoCs, however this same GPIO
HW has been in iPhones dating back to at least the iPhone 7 (2016). If
there are minor changes we can add a new compatible, and if there is new
HW in the future we can introduce a new file for it.

[...]

> > +	prev = readl(ppin);
> > +	cfg = (prev & ~clr) | set;
> > +
> > +	if(!(prev & REG_GPIOx_CFG_DONE))
> > +		writel(cfg & ~REG_GPIOx_CFG_DONE, ppin);
> > +	writel(cfg, ppin);
> 
> Is it IP requirement to have sequential writes? Can it be done in one?
We unfortunately don't have the documentation for this HW, so this behaviour is
based on observing what macOS does.

[...]

> > +	if(!of_find_property(node, "gpio-controller", NULL)) {
> > +		dev_err(pctl->dev, "Apple GPIO must have 'gpio-controller' property.\n");
> > +		return -ENODEV;
> > +	}
> 
> How is it possible?
This is possible if booted with an invalid DTB. "gpio-controller" is a
required property according to Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml.

[...]

> 
> ...
> 
> > +	if (of_find_property(node, "interrupt-controller", NULL)) {
> 
> Are you sure you need this check and OF core doesn't provide a generic way for this?
> 
I don't think so, and pinctrl-equilibrium.c does something similar in
`gpiochip_setup`.

[...] 

> > +	if (of_parse_phandle_with_fixed_args(pdev->dev.of_node, "gpio-ranges",
> > +			3, 0, &pinspec)) {
> > +		dev_err(&pdev->dev, "gpio-ranges property not found\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	pctl->npins = pinspec.args[2];
> > +	pin_base = pinspec.args[1];
> 
> 
> Isn't this being provided by pin control?
Not that I am aware of. It is a similar pattern to other pinctrl drivers
like pinctrl-rza1.c and pinctrl-npcm7xx.c. The driver needs to get the
number of pins/base from the DT to setup the internal data structures.

Thanks,
Joey

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-25 13:44     ` Joey Gouly
@ 2021-09-26  5:08       ` Andy Shevchenko
  2021-09-26 12:48         ` Linus Walleij
  0 siblings, 1 reply; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-26  5:08 UTC (permalink / raw)
  To: Joey Gouly
  Cc: Andy Shevchenko, open list:GPIO SUBSYSTEM, Linus Walleij,
	Hector Martin, Marc Zyngier, Alyssa Rosenzweig, Sven Peter, nd,
	Stan Skowronek

On Sat, Sep 25, 2021 at 4:45 PM Joey Gouly <joey.gouly@arm.com> wrote:
> On Wed, Sep 22, 2021 at 10:20:39AM +0300, Andy Shevchenko wrote:

...

> > > +F: drivers/pinctrl/pinctrl-apple-gpio.c
> >
> > Are you sure it's a good naming? Have you guaranteed that next Apple silicons
> > will use the same / compatible IP?
> We don't know what will be in future Apple SoCs, however this same GPIO
> HW has been in iPhones dating back to at least the iPhone 7 (2016). If
> there are minor changes we can add a new compatible, and if there is new
> HW in the future we can introduce a new file for it.

Do we have a chip name? For example, for M1 it's T8101 or something
like that. I would use a chip name/family rather than a broad brand
name.

...

> > > +   prev = readl(ppin);
> > > +   cfg = (prev & ~clr) | set;
> > > +
> > > +   if(!(prev & REG_GPIOx_CFG_DONE))
> > > +           writel(cfg & ~REG_GPIOx_CFG_DONE, ppin);
> > > +   writel(cfg, ppin);
> >
> > Is it IP requirement to have sequential writes? Can it be done in one?
> We unfortunately don't have the documentation for this HW, so this behaviour is
> based on observing what macOS does.

So, then there are following remarks/questions:
1/ Have you tested when it does a single write?
2/ If it doesn't work, this piece deserves a good comment.

...

> > > +   if(!of_find_property(node, "gpio-controller", NULL)) {
> > > +           dev_err(pctl->dev, "Apple GPIO must have 'gpio-controller' property.\n");
> > > +           return -ENODEV;
> > > +   }
> >
> > How is it possible?
> This is possible if booted with an invalid DTB. "gpio-controller" is a
> required property according to Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml.

No, we don't do silly checks. Compare to other pin control drivers. If
DTB is wrong, you will see it sooner or later.

...

> > > +   if (of_find_property(node, "interrupt-controller", NULL)) {
> >
> > Are you sure you need this check and OF core doesn't provide a generic way for this?
> >
> I don't think so, and pinctrl-equilibrium.c does something similar in
> `gpiochip_setup`.

Linus? Do we really need this?

...

> > > +   if (of_parse_phandle_with_fixed_args(pdev->dev.of_node, "gpio-ranges",
> > > +                   3, 0, &pinspec)) {
> > > +           dev_err(&pdev->dev, "gpio-ranges property not found\n");
> > > +           return -EINVAL;
> > > +   }
> > > +
> > > +   pctl->npins = pinspec.args[2];
> > > +   pin_base = pinspec.args[1];
> >
> >
> > Isn't this being provided by pin control?
> Not that I am aware of. It is a similar pattern to other pinctrl drivers
> like pinctrl-rza1.c and pinctrl-npcm7xx.c. The driver needs to get the
> number of pins/base from the DT to setup the internal data structures.

So, maybe you need to refactor the pin control core first and provide
some stubs that will serve your purposes, but to me it sounds weird to
have all these checks.

Linus, what is your opinion / input here?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26  5:08       ` Andy Shevchenko
@ 2021-09-26 12:48         ` Linus Walleij
  2021-09-26 12:56           ` Sven Peter
  2021-09-28 18:21           ` Joey Gouly
  0 siblings, 2 replies; 24+ messages in thread
From: Linus Walleij @ 2021-09-26 12:48 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Joey Gouly, Andy Shevchenko, open list:GPIO SUBSYSTEM,
	Hector Martin, Marc Zyngier, Alyssa Rosenzweig, Sven Peter, nd,
	Stan Skowronek

On Sun, Sep 26, 2021 at 7:09 AM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Sat, Sep 25, 2021 at 4:45 PM Joey Gouly <joey.gouly@arm.com> wrote:
> > On Wed, Sep 22, 2021 at 10:20:39AM +0300, Andy Shevchenko wrote:

> > > > +   if (of_find_property(node, "interrupt-controller", NULL)) {
> > >
> > > Are you sure you need this check and OF core doesn't provide a generic way for this?
> > >
> > I don't think so, and pinctrl-equilibrium.c does something similar in
> > `gpiochip_setup`.
>
> Linus? Do we really need this?

I don't really see this as necessary, we don't need to check everything.
Not that it hurts either, so I would say maintainer preference?

> > > > +   if (of_parse_phandle_with_fixed_args(pdev->dev.of_node, "gpio-ranges",
> > > > +                   3, 0, &pinspec)) {
> > > > +           dev_err(&pdev->dev, "gpio-ranges property not found\n");
> > > > +           return -EINVAL;
> > > > +   }
> > > > +
> > > > +   pctl->npins = pinspec.args[2];
> > > > +   pin_base = pinspec.args[1];
> > >
> > >
> > > Isn't this being provided by pin control?
> >
> > Not that I am aware of. It is a similar pattern to other pinctrl drivers
> > like pinctrl-rza1.c and pinctrl-npcm7xx.c. The driver needs to get the
> > number of pins/base from the DT to setup the internal data structures.
>
> So, maybe you need to refactor the pin control core first and provide
> some stubs that will serve your purposes, but to me it sounds weird to
> have all these checks.
>
> Linus, what is your opinion / input here?

I don't remember right now how the review was going on the
mentioned drivers.

I did imagine that of_gpiochip_add_pin_range() would be the
sole parser of this, and drivers would then use the infrastructure
for any necessary cross-reference between the subsystems,
not second-code it.

What is it that you really need to do here?

I think npins should be known from the compatible (we know that
this version of the SoC has so and so many pins) and the base
should always be 0? It's not like we have several pin controllers
of this type in the SoC is it?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 12:48         ` Linus Walleij
@ 2021-09-26 12:56           ` Sven Peter
  2021-09-26 13:10             ` Linus Walleij
  2021-09-28 18:21           ` Joey Gouly
  1 sibling, 1 reply; 24+ messages in thread
From: Sven Peter @ 2021-09-26 12:56 UTC (permalink / raw)
  To: Linus Walleij, Andy Shevchenko
  Cc: Joey Gouly, Andy Shevchenko, open list:GPIO SUBSYSTEM,
	Hector Martin, Marc Zyngier, Alyssa Rosenzweig, nd,
	Stan Skowronek

Hi,

On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:
> I think npins should be known from the compatible (we know that
> this version of the SoC has so and so many pins) and the base
> should always be 0? It's not like we have several pin controllers
> of this type in the SoC is it?

I've just checked: Looks like there are four different pin controllers of
this type with a different number of pins each in Apple's device tree for
the M1.


Best,


Sven

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 12:56           ` Sven Peter
@ 2021-09-26 13:10             ` Linus Walleij
  2021-09-26 14:35               ` Sven Peter
  0 siblings, 1 reply; 24+ messages in thread
From: Linus Walleij @ 2021-09-26 13:10 UTC (permalink / raw)
  To: Sven Peter
  Cc: Andy Shevchenko, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:

> > I think npins should be known from the compatible (we know that
> > this version of the SoC has so and so many pins) and the base
> > should always be 0? It's not like we have several pin controllers
> > of this type in the SoC is it?
>
> I've just checked: Looks like there are four different pin controllers of
> this type with a different number of pins each in Apple's device tree for
> the M1.

So we need to understand this hardware: is this something like
south/north/east/west, so the pins are oriented around the chip?

I would suspect they should then be compatibles:
apple,t8103-pinctrl-north, apple,t8103-pinctrl
apple,t8103-pinctrl-south, apple,t8103-pinctrl
apple,t8103-pinctrl-west, apple,t8103-pinctrl
apple,t8103-pinctrl-east, apple,t8103-pinctrl

going from specific to general signifying that we know which one
we are dealing with and then we know the npins etc.

This also gives a normal grouping of functions associated with
pins and the portion of the SoC, see for
example drivers/pinctrl/intel/pinctrl-broxton.c.

This shows that it might have been a bad idea to define the
pins as opaque, because now that is hiding the fact that
these pins are grouped in four distinct sets.
APPLE_PINMUX(pin, func)

Should rather have been APPLE_PINMUX(cardinal, pin, func)
where cardinal would be 0..3 for north, south, west, east.

This is a bit of guessing actually, but we should definitely
try to make the driver reflect the reality and not over-generalize.
If these four blocks in the SoC are different, they should have
different compatible strings, because they are not, by
definition, compatible.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 13:10             ` Linus Walleij
@ 2021-09-26 14:35               ` Sven Peter
  2021-09-26 16:28                 ` Andy Shevchenko
  2021-09-27 23:34                 ` Linus Walleij
  0 siblings, 2 replies; 24+ messages in thread
From: Sven Peter @ 2021-09-26 14:35 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Andy Shevchenko, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek



On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
> On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
>> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:
>
>> > I think npins should be known from the compatible (we know that
>> > this version of the SoC has so and so many pins) and the base
>> > should always be 0? It's not like we have several pin controllers
>> > of this type in the SoC is it?
>>
>> I've just checked: Looks like there are four different pin controllers of
>> this type with a different number of pins each in Apple's device tree for
>> the M1.
>
> So we need to understand this hardware: is this something like
> south/north/east/west, so the pins are oriented around the chip?
>
> I would suspect they should then be compatibles:
> apple,t8103-pinctrl-north, apple,t8103-pinctrl
> apple,t8103-pinctrl-south, apple,t8103-pinctrl
> apple,t8103-pinctrl-west, apple,t8103-pinctrl
> apple,t8103-pinctrl-east, apple,t8103-pinctrl
>
> going from specific to general signifying that we know which one
> we are dealing with and then we know the npins etc.

Apple calls those four controllers "gpio", "nub-gpio", "smc-gpio"
and "aop-gpio". SMC is their system management controller and AOP
is their "always-on processor". No idea what "nub-gpio" is.

>
> This also gives a normal grouping of functions associated with
> pins and the portion of the SoC, see for
> example drivers/pinctrl/intel/pinctrl-broxton.c.
>
> This shows that it might have been a bad idea to define the
> pins as opaque, because now that is hiding the fact that
> these pins are grouped in four distinct sets.
> APPLE_PINMUX(pin, func)
>
> Should rather have been APPLE_PINMUX(cardinal, pin, func)
> where cardinal would be 0..3 for north, south, west, east.
>
> This is a bit of guessing actually, but we should definitely
> try to make the driver reflect the reality and not over-generalize.
> If these four blocks in the SoC are different, they should have
> different compatible strings, because they are not, by
> definition, compatible.

I'd prefer to have a single compatible and get the npins from some
property and I don't think that's necessarily over-generalizing.
AFAICT Apple has been using the exact same MMIO interface for years
and I'd expect them to continue using it in the future. The only thing
that seems to change is the number of pins available and their assignment.
If we just have a single compatible we can likely support the M1X/2 or
however Apple calls the next SoCs with just a simple DTB change without
touching any driver code.



Best,

Sven


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 14:35               ` Sven Peter
@ 2021-09-26 16:28                 ` Andy Shevchenko
  2021-09-27  5:45                   ` Sven Peter
  2021-09-27  8:46                   ` Alyssa Rosenzweig
  2021-09-27 23:34                 ` Linus Walleij
  1 sibling, 2 replies; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-26 16:28 UTC (permalink / raw)
  To: Sven Peter
  Cc: Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

On Sun, Sep 26, 2021 at 5:36 PM Sven Peter <sven@svenpeter.dev> wrote:
> On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
> > On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
> >> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:
> >
> >> > I think npins should be known from the compatible (we know that
> >> > this version of the SoC has so and so many pins) and the base
> >> > should always be 0? It's not like we have several pin controllers
> >> > of this type in the SoC is it?
> >>
> >> I've just checked: Looks like there are four different pin controllers of
> >> this type with a different number of pins each in Apple's device tree for
> >> the M1.
> >
> > So we need to understand this hardware: is this something like
> > south/north/east/west, so the pins are oriented around the chip?
> >
> > I would suspect they should then be compatibles:
> > apple,t8103-pinctrl-north, apple,t8103-pinctrl
> > apple,t8103-pinctrl-south, apple,t8103-pinctrl
> > apple,t8103-pinctrl-west, apple,t8103-pinctrl
> > apple,t8103-pinctrl-east, apple,t8103-pinctrl
> >
> > going from specific to general signifying that we know which one
> > we are dealing with and then we know the npins etc.
>
> Apple calls those four controllers "gpio", "nub-gpio", "smc-gpio"
> and "aop-gpio". SMC is their system management controller and AOP
> is their "always-on processor". No idea what "nub-gpio" is.

It's similar to what we have in Baytrail/Cherrytrail.
AOP -> SUS
SMC -> ...

nub is probably related to some type of hub (or maybe simple typo, or
typo on purpose?).

> > This also gives a normal grouping of functions associated with
> > pins and the portion of the SoC, see for
> > example drivers/pinctrl/intel/pinctrl-broxton.c.
> >
> > This shows that it might have been a bad idea to define the
> > pins as opaque, because now that is hiding the fact that
> > these pins are grouped in four distinct sets.
> > APPLE_PINMUX(pin, func)
> >
> > Should rather have been APPLE_PINMUX(cardinal, pin, func)
> > where cardinal would be 0..3 for north, south, west, east.
> >
> > This is a bit of guessing actually, but we should definitely
> > try to make the driver reflect the reality and not over-generalize.
> > If these four blocks in the SoC are different, they should have
> > different compatible strings, because they are not, by
> > definition, compatible.
>
> I'd prefer to have a single compatible and get the npins from some
> property and I don't think that's necessarily over-generalizing.
> AFAICT Apple has been using the exact same MMIO interface for years
> and I'd expect them to continue using it in the future. The only thing
> that seems to change is the number of pins available and their assignment.
> If we just have a single compatible we can likely support the M1X/2 or
> however Apple calls the next SoCs with just a simple DTB change without
> touching any driver code.

Hmm... Dunno the details, but at least AOP GPIO is definitely ca[able
of waking a system from a deep sleep (that's what SUS == suspend do on
Intel). Haven't checked if you implemented ->irq_set_wake() callbacks,
though.

And I don't know if the pin's in the rest of the GPIO blocks have the
wake-source capable pins. Also I don't know if it's fine to have one
compatible string if you really know that the difference is the amount
of pins and nothing else (like crucial properties being changed).

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 16:28                 ` Andy Shevchenko
@ 2021-09-27  5:45                   ` Sven Peter
  2021-09-27  9:00                     ` Andy Shevchenko
  2021-09-27  8:46                   ` Alyssa Rosenzweig
  1 sibling, 1 reply; 24+ messages in thread
From: Sven Peter @ 2021-09-27  5:45 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

Hi Andy,

On Sun, Sep 26, 2021, at 18:28, Andy Shevchenko wrote:
> On Sun, Sep 26, 2021 at 5:36 PM Sven Peter <sven@svenpeter.dev> wrote:
>> On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
>> > On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
>> >> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:
>> >
>> >> > I think npins should be known from the compatible (we know that
>> >> > this version of the SoC has so and so many pins) and the base
>> >> > should always be 0? It's not like we have several pin controllers
>> >> > of this type in the SoC is it?
>> >>
>> >> I've just checked: Looks like there are four different pin controllers of
>> >> this type with a different number of pins each in Apple's device tree for
>> >> the M1.
>> >
>> > So we need to understand this hardware: is this something like
>> > south/north/east/west, so the pins are oriented around the chip?
>> >
>> > I would suspect they should then be compatibles:
>> > apple,t8103-pinctrl-north, apple,t8103-pinctrl
>> > apple,t8103-pinctrl-south, apple,t8103-pinctrl
>> > apple,t8103-pinctrl-west, apple,t8103-pinctrl
>> > apple,t8103-pinctrl-east, apple,t8103-pinctrl
>> >
>> > going from specific to general signifying that we know which one
>> > we are dealing with and then we know the npins etc.
>>
>> Apple calls those four controllers "gpio", "nub-gpio", "smc-gpio"
>> and "aop-gpio". SMC is their system management controller and AOP
>> is their "always-on processor". No idea what "nub-gpio" is.
>
> It's similar to what we have in Baytrail/Cherrytrail.
> AOP -> SUS
> SMC -> ...

Interesting! I'll take a look at those.
 
>
> nub is probably related to some type of hub (or maybe simple typo, or
> typo on purpose?).
>
>> > This also gives a normal grouping of functions associated with
>> > pins and the portion of the SoC, see for
>> > example drivers/pinctrl/intel/pinctrl-broxton.c.
>> >
>> > This shows that it might have been a bad idea to define the
>> > pins as opaque, because now that is hiding the fact that
>> > these pins are grouped in four distinct sets.
>> > APPLE_PINMUX(pin, func)
>> >
>> > Should rather have been APPLE_PINMUX(cardinal, pin, func)
>> > where cardinal would be 0..3 for north, south, west, east.
>> >
>> > This is a bit of guessing actually, but we should definitely
>> > try to make the driver reflect the reality and not over-generalize.
>> > If these four blocks in the SoC are different, they should have
>> > different compatible strings, because they are not, by
>> > definition, compatible.
>>
>> I'd prefer to have a single compatible and get the npins from some
>> property and I don't think that's necessarily over-generalizing.
>> AFAICT Apple has been using the exact same MMIO interface for years
>> and I'd expect them to continue using it in the future. The only thing
>> that seems to change is the number of pins available and their assignment.
>> If we just have a single compatible we can likely support the M1X/2 or
>> however Apple calls the next SoCs with just a simple DTB change without
>> touching any driver code.
>
> Hmm... Dunno the details, but at least AOP GPIO is definitely ca[able
> of waking a system from a deep sleep (that's what SUS == suspend do on
> Intel). Haven't checked if you implemented ->irq_set_wake() callbacks,
> though.

I don't think Joey implemented the set_wake callback because we didn't
even consider that the AOP GPIOs might be able to wake the system from
deep sleep. I'll see if I can figure out some details about that though.

>
> And I don't know if the pin's in the rest of the GPIO blocks have the
> wake-source capable pins. Also I don't know if it's fine to have one
> compatible string if you really know that the difference is the amount
> of pins and nothing else (like crucial properties being changed).

Yeah, I don't know either. Another thing we could do is have the base
compatible just support the maximum number of pins supported by the MMIO
space and only limit that (and possibly add wake-capable pins or other
different properties if there are any) for the more specific ones.


Best,


Sven

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 16:28                 ` Andy Shevchenko
  2021-09-27  5:45                   ` Sven Peter
@ 2021-09-27  8:46                   ` Alyssa Rosenzweig
  2021-09-27  8:55                     ` Andy Shevchenko
  1 sibling, 1 reply; 24+ messages in thread
From: Alyssa Rosenzweig @ 2021-09-27  8:46 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Sven Peter, Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

> > Apple calls those four controllers "gpio", "nub-gpio", "smc-gpio"
> > and "aop-gpio". SMC is their system management controller and AOP
> > is their "always-on processor". No idea what "nub-gpio" is.
> 
> It's similar to what we have in Baytrail/Cherrytrail.
> AOP -> SUS
> SMC -> ...
> 
> nub is probably related to some type of hub (or maybe simple typo, or
> typo on purpose?).

Unlikely a typo. "nub" is an Apple term. In software, an XNU (macOS)
kernel driver has a "nub" for exposing its public API. I don't know what
it means for hardware but very likely intentional.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-27  8:46                   ` Alyssa Rosenzweig
@ 2021-09-27  8:55                     ` Andy Shevchenko
  0 siblings, 0 replies; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-27  8:55 UTC (permalink / raw)
  To: Alyssa Rosenzweig
  Cc: Sven Peter, Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

On Mon, Sep 27, 2021 at 11:46 AM Alyssa Rosenzweig <alyssa@collabora.com> wrote:

...

> > nub is probably related to some type of hub (or maybe simple typo, or
> > typo on purpose?).
>
> Unlikely a typo. "nub" is an Apple term. In software, an XNU (macOS)
> kernel driver has a "nub" for exposing its public API. I don't know what
> it means for hardware but very likely intentional.

Good to know!

So, it would be nice to have a better understanding of what it's exactly...

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-27  5:45                   ` Sven Peter
@ 2021-09-27  9:00                     ` Andy Shevchenko
  2021-09-27  9:27                       ` Hans de Goede
  0 siblings, 1 reply; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-27  9:00 UTC (permalink / raw)
  To: Sven Peter, Hans de Goede
  Cc: Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

+Cc: Hans (just for a bit offtopic comment below)

On Mon, Sep 27, 2021 at 8:46 AM Sven Peter <sven@svenpeter.dev> wrote:
> On Sun, Sep 26, 2021, at 18:28, Andy Shevchenko wrote:
> > On Sun, Sep 26, 2021 at 5:36 PM Sven Peter <sven@svenpeter.dev> wrote:
> >> On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
> >> > On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
> >> >> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:

...

> >> I'd prefer to have a single compatible and get the npins from some
> >> property and I don't think that's necessarily over-generalizing.
> >> AFAICT Apple has been using the exact same MMIO interface for years
> >> and I'd expect them to continue using it in the future. The only thing
> >> that seems to change is the number of pins available and their assignment.
> >> If we just have a single compatible we can likely support the M1X/2 or
> >> however Apple calls the next SoCs with just a simple DTB change without
> >> touching any driver code.
> >
> > Hmm... Dunno the details, but at least AOP GPIO is definitely ca[able
> > of waking a system from a deep sleep (that's what SUS == suspend do on
> > Intel). Haven't checked if you implemented ->irq_set_wake() callbacks,
> > though.
>
> I don't think Joey implemented the set_wake callback because we didn't
> even consider that the AOP GPIOs might be able to wake the system from
> deep sleep. I'll see if I can figure out some details about that though.

I have checked Intel drivers and above mentioned do not implement
->irq_set_wake() callback. Hmm... Maybe Hans can share his thoughts
why it's so
(note, the Skylake and newest are all based on pinctrl-intel.c which
implements it. So does Merrifield) and if we also need to consider
adding it.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-27  9:00                     ` Andy Shevchenko
@ 2021-09-27  9:27                       ` Hans de Goede
  2021-09-27  9:43                         ` Andy Shevchenko
  0 siblings, 1 reply; 24+ messages in thread
From: Hans de Goede @ 2021-09-27  9:27 UTC (permalink / raw)
  To: Andy Shevchenko, Sven Peter
  Cc: Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

Hi,

On 9/27/21 11:00 AM, Andy Shevchenko wrote:
> +Cc: Hans (just for a bit offtopic comment below)
> 
> On Mon, Sep 27, 2021 at 8:46 AM Sven Peter <sven@svenpeter.dev> wrote:
>> On Sun, Sep 26, 2021, at 18:28, Andy Shevchenko wrote:
>>> On Sun, Sep 26, 2021 at 5:36 PM Sven Peter <sven@svenpeter.dev> wrote:
>>>> On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
>>>>> On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
>>>>>> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:
> 
> ...
> 
>>>> I'd prefer to have a single compatible and get the npins from some
>>>> property and I don't think that's necessarily over-generalizing.
>>>> AFAICT Apple has been using the exact same MMIO interface for years
>>>> and I'd expect them to continue using it in the future. The only thing
>>>> that seems to change is the number of pins available and their assignment.
>>>> If we just have a single compatible we can likely support the M1X/2 or
>>>> however Apple calls the next SoCs with just a simple DTB change without
>>>> touching any driver code.
>>>
>>> Hmm... Dunno the details, but at least AOP GPIO is definitely ca[able
>>> of waking a system from a deep sleep (that's what SUS == suspend do on
>>> Intel). Haven't checked if you implemented ->irq_set_wake() callbacks,
>>> though.
>>
>> I don't think Joey implemented the set_wake callback because we didn't
>> even consider that the AOP GPIOs might be able to wake the system from
>> deep sleep. I'll see if I can figure out some details about that though.
> 
> I have checked Intel drivers and above mentioned do not implement
> ->irq_set_wake() callback. Hmm... Maybe Hans can share his thoughts
> why it's so
> (note, the Skylake and newest are all based on pinctrl-intel.c which
> implements it. So does Merrifield) and if we also need to consider
> adding it.

Bay Trail and Cherry Trail always use suspend2idle, which means any
IRQ is a wake IRQ, since the CPU is in a S0ix (deep-idle, rather
then full suspended) state.

Drivers still need to make irq_set_irq_wake() calls
though, to avoid the IRQ code disabling the IRQ on suspend.

To allow those calls to succeed the baytrail and cherryview
pinctrl drivers set IRQCHIP_SKIP_SET_WAKE in their irqchip.flags.

There are also some more standard (non tablet targetting)
CPUs which are using the same GPIO IP block, e.g.
the Celeron N2840 uses the pinctrl-baytrail.c code but
laptops using this will typically use normal S3 suspend.

I assume that in this case configuring which IRQs are wakeup
sources is actually controlled the BIOS, since S3 suspend is
heavily BIOS assisted. I would not even be surprised if the
BIOS even completely reprograms all IRQ settings (including
IRQs left enabled) on suspend.

Regards,

Hans


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-27  9:27                       ` Hans de Goede
@ 2021-09-27  9:43                         ` Andy Shevchenko
  0 siblings, 0 replies; 24+ messages in thread
From: Andy Shevchenko @ 2021-09-27  9:43 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Sven Peter, Linus Walleij, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

On Mon, Sep 27, 2021 at 12:27 PM Hans de Goede <hdegoede@redhat.com> wrote:
> On 9/27/21 11:00 AM, Andy Shevchenko wrote:
> > On Mon, Sep 27, 2021 at 8:46 AM Sven Peter <sven@svenpeter.dev> wrote:
> >> On Sun, Sep 26, 2021, at 18:28, Andy Shevchenko wrote:
> >>> On Sun, Sep 26, 2021 at 5:36 PM Sven Peter <sven@svenpeter.dev> wrote:
> >>>> On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
> >>>>> On Sun, Sep 26, 2021 at 2:56 PM Sven Peter <sven@svenpeter.dev> wrote:
> >>>>>> On Sun, Sep 26, 2021, at 14:48, Linus Walleij wrote:

...

> >>> Hmm... Dunno the details, but at least AOP GPIO is definitely ca[able
> >>> of waking a system from a deep sleep (that's what SUS == suspend do on
> >>> Intel). Haven't checked if you implemented ->irq_set_wake() callbacks,
> >>> though.
> >>
> >> I don't think Joey implemented the set_wake callback because we didn't
> >> even consider that the AOP GPIOs might be able to wake the system from
> >> deep sleep. I'll see if I can figure out some details about that though.
> >
> > I have checked Intel drivers and above mentioned do not implement
> > ->irq_set_wake() callback. Hmm... Maybe Hans can share his thoughts
> > why it's so
> > (note, the Skylake and newest are all based on pinctrl-intel.c which
> > implements it. So does Merrifield) and if we also need to consider
> > adding it.
>
> Bay Trail and Cherry Trail always use suspend2idle, which means any
> IRQ is a wake IRQ, since the CPU is in a S0ix (deep-idle, rather
> then full suspended) state.
>
> Drivers still need to make irq_set_irq_wake() calls
> though, to avoid the IRQ code disabling the IRQ on suspend.
>
> To allow those calls to succeed the baytrail and cherryview
> pinctrl drivers set IRQCHIP_SKIP_SET_WAKE in their irqchip.flags.
>
> There are also some more standard (non tablet targetting)
> CPUs which are using the same GPIO IP block, e.g.
> the Celeron N2840 uses the pinctrl-baytrail.c code but
> laptops using this will typically use normal S3 suspend.
>
> I assume that in this case configuring which IRQs are wakeup
> sources is actually controlled the BIOS, since S3 suspend is
> heavily BIOS assisted. I would not even be surprised if the
> BIOS even completely reprograms all IRQ settings (including
> IRQs left enabled) on suspend.

Thank you, Hans!
I will try not to forget this, but it makes me wonder if we may
collect this kind of information in some README-like file inside the
source code.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 14:35               ` Sven Peter
  2021-09-26 16:28                 ` Andy Shevchenko
@ 2021-09-27 23:34                 ` Linus Walleij
  2021-09-28 21:20                   ` Joey Gouly
  1 sibling, 1 reply; 24+ messages in thread
From: Linus Walleij @ 2021-09-27 23:34 UTC (permalink / raw)
  To: Sven Peter
  Cc: Andy Shevchenko, Joey Gouly, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

On Sun, Sep 26, 2021 at 4:36 PM Sven Peter <sven@svenpeter.dev> wrote:
> On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:

> > If these four blocks in the SoC are different, they should have
> > different compatible strings, because they are not, by
> > definition, compatible.
>
> I'd prefer to have a single compatible and get the npins from some
> property and I don't think that's necessarily over-generalizing.
> AFAICT Apple has been using the exact same MMIO interface for years
> and I'd expect them to continue using it in the future. The only thing
> that seems to change is the number of pins available and their assignment.
> If we just have a single compatible we can likely support the M1X/2 or
> however Apple calls the next SoCs with just a simple DTB change without
> touching any driver code.

Admittedly the word "compatible" in DT context is a bit fuzzy around the
edges. Sometimes it is more like "parameterizable" which is what you
are saying here.

I don't have a very strong opinion on it, both approaches are possible.
Being able to define new SoCs are not always helpful for developers
as the data in DT can become opaque and hard to understand if it
is too general.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-26 12:48         ` Linus Walleij
  2021-09-26 12:56           ` Sven Peter
@ 2021-09-28 18:21           ` Joey Gouly
  2021-09-28 21:50             ` Linus Walleij
  1 sibling, 1 reply; 24+ messages in thread
From: Joey Gouly @ 2021-09-28 18:21 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Andy Shevchenko, Andy Shevchenko, open list:GPIO SUBSYSTEM,
	Hector Martin, Marc Zyngier, Alyssa Rosenzweig, Sven Peter, nd,
	Stan Skowronek

Hi,

On Sun, Sep 26, 2021 at 02:48:18PM +0200, Linus Walleij wrote:
> On Sun, Sep 26, 2021 at 7:09 AM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
> > On Sat, Sep 25, 2021 at 4:45 PM Joey Gouly <joey.gouly@arm.com> wrote:
> > > On Wed, Sep 22, 2021 at 10:20:39AM +0300, Andy Shevchenko wrote:
> 
> > > > > +   if (of_find_property(node, "interrupt-controller", NULL)) {
> > > >
> > > > Are you sure you need this check and OF core doesn't provide a generic way for this?
> > > >
> > > I don't think so, and pinctrl-equilibrium.c does something similar in
> > > `gpiochip_setup`.
> >
> > Linus? Do we really need this?
> 
> I don't really see this as necessary, we don't need to check everything.
> Not that it hurts either, so I would say maintainer preference?
> 
I'm unsure if that means you (Linus), or Hector Martin as I put this
file under the "ARM/APPLE MACHINE SUPPORT" section in MAINTAINERS.

> > > > > +   if (of_parse_phandle_with_fixed_args(pdev->dev.of_node, "gpio-ranges",
> > > > > +                   3, 0, &pinspec)) {
> > > > > +           dev_err(&pdev->dev, "gpio-ranges property not found\n");
> > > > > +           return -EINVAL;
> > > > > +   }
> > > > > +
> > > > > +   pctl->npins = pinspec.args[2];
> > > > > +   pin_base = pinspec.args[1];
> > > >
> > > >
> > > > Isn't this being provided by pin control?
> > >
> > > Not that I am aware of. It is a similar pattern to other pinctrl drivers
> > > like pinctrl-rza1.c and pinctrl-npcm7xx.c. The driver needs to get the
> > > number of pins/base from the DT to setup the internal data structures.
> >
> > So, maybe you need to refactor the pin control core first and provide
> > some stubs that will serve your purposes, but to me it sounds weird to
> > have all these checks.
> >
> > Linus, what is your opinion / input here?
> 
> I don't remember right now how the review was going on the
> mentioned drivers.
> 
> I did imagine that of_gpiochip_add_pin_range() would be the
> sole parser of this, and drivers would then use the infrastructure
> for any necessary cross-reference between the subsystems,
> not second-code it.
> 
> What is it that you really need to do here?
> 
> I think npins should be known from the compatible (we know that
> this version of the SoC has so and so many pins) and the base
> should always be 0? It's not like we have several pin controllers
> of this type in the SoC is it?
All we need is the number of GPIOs from the DT now.
I got a bit confused with the 'base' here, locally I have removed the
'pin_base' variable and usage. I was confusing it with the `gpio_chip.base` field,
however that seems to be about the internal GPIO numbering.

Thanks,
Joey

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-27 23:34                 ` Linus Walleij
@ 2021-09-28 21:20                   ` Joey Gouly
  0 siblings, 0 replies; 24+ messages in thread
From: Joey Gouly @ 2021-09-28 21:20 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Sven Peter, Andy Shevchenko, Andy Shevchenko,
	open list:GPIO SUBSYSTEM, Hector Martin, Marc Zyngier,
	Alyssa Rosenzweig, nd, Stan Skowronek

Hello!

On Tue, Sep 28, 2021 at 01:34:39AM +0200, Linus Walleij wrote:
> On Sun, Sep 26, 2021 at 4:36 PM Sven Peter <sven@svenpeter.dev> wrote:
> > On Sun, Sep 26, 2021, at 15:10, Linus Walleij wrote:
> 
> > > If these four blocks in the SoC are different, they should have
> > > different compatible strings, because they are not, by
> > > definition, compatible.
> >
> > I'd prefer to have a single compatible and get the npins from some
> > property and I don't think that's necessarily over-generalizing.
> > AFAICT Apple has been using the exact same MMIO interface for years
> > and I'd expect them to continue using it in the future. The only thing
> > that seems to change is the number of pins available and their assignment.
> > If we just have a single compatible we can likely support the M1X/2 or
> > however Apple calls the next SoCs with just a simple DTB change without
> > touching any driver code.
> 
> Admittedly the word "compatible" in DT context is a bit fuzzy around the
> edges. Sometimes it is more like "parameterizable" which is what you
> are saying here.
> 
> I don't have a very strong opinion on it, both approaches are possible.
> Being able to define new SoCs are not always helpful for developers
> as the data in DT can become opaque and hard to understand if it
> is too general.
I think we want to try avoid hardcoding big lists of GPIO pins,
especially when we don't know what most of them are used for yet.
As Sven has said it would be nice to not need to change the driver if
future SoCs have slightly different pin configurations or maybe even
extra pinctrl hardware blocks.

I have a v2 of this series mostly ready, if it's decided it's ok to go
with the current approach.

Thanks,
Joey

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v1 1/1] pinctrl: add pinctrl/GPIO driver for Apple SoCs
  2021-09-28 18:21           ` Joey Gouly
@ 2021-09-28 21:50             ` Linus Walleij
  0 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-09-28 21:50 UTC (permalink / raw)
  To: Joey Gouly
  Cc: Andy Shevchenko, Andy Shevchenko, open list:GPIO SUBSYSTEM,
	Hector Martin, Marc Zyngier, Alyssa Rosenzweig, Sven Peter, nd,
	Stan Skowronek

On Tue, Sep 28, 2021 at 8:21 PM Joey Gouly <joey.gouly@arm.com> wrote:

> > > Linus? Do we really need this?
> >
> > I don't really see this as necessary, we don't need to check everything.
> > Not that it hurts either, so I would say maintainer preference?
> >
> I'm unsure if that means you (Linus), or Hector Martin as I put this
> file under the "ARM/APPLE MACHINE SUPPORT" section in MAINTAINERS.

Your preference, I am sure that even if Hector certainly may want to
chime in, he expects the code author (you) to assume a bit of
ownership of this piece of code for the foreseeable future,
so do what you consider reasonable.

> > I think npins should be known from the compatible (we know that
> > this version of the SoC has so and so many pins) and the base
> > should always be 0? It's not like we have several pin controllers
> > of this type in the SoC is it?
>
> All we need is the number of GPIOs from the DT now.
> I got a bit confused with the 'base' here, locally I have removed the
> 'pin_base' variable and usage. I was confusing it with the `gpio_chip.base` field,
> however that seems to be about the internal GPIO numbering.

The GPIO bindings have a standardized "ngpios" property that
indicates if you use less than the HW max number of GPIO
lines (roughly).

This is about pins rather, so something custom like
apple,npins = <...>;
could be used in that case.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2021-09-28 21:51 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-21 22:29 [PATCH v1 0/1] pinctrl/GPIO driver for Apple SoCs Joey Gouly
2021-09-21 22:29 ` [PATCH v1 1/1] pinctrl: add " Joey Gouly
2021-09-22  7:20   ` Andy Shevchenko
2021-09-25 13:44     ` Joey Gouly
2021-09-26  5:08       ` Andy Shevchenko
2021-09-26 12:48         ` Linus Walleij
2021-09-26 12:56           ` Sven Peter
2021-09-26 13:10             ` Linus Walleij
2021-09-26 14:35               ` Sven Peter
2021-09-26 16:28                 ` Andy Shevchenko
2021-09-27  5:45                   ` Sven Peter
2021-09-27  9:00                     ` Andy Shevchenko
2021-09-27  9:27                       ` Hans de Goede
2021-09-27  9:43                         ` Andy Shevchenko
2021-09-27  8:46                   ` Alyssa Rosenzweig
2021-09-27  8:55                     ` Andy Shevchenko
2021-09-27 23:34                 ` Linus Walleij
2021-09-28 21:20                   ` Joey Gouly
2021-09-28 18:21           ` Joey Gouly
2021-09-28 21:50             ` Linus Walleij
2021-09-22 13:09   ` Marc Zyngier
2021-09-22 23:58     ` Linus Walleij
2021-09-22  6:59 ` [PATCH v1 0/1] " Andy Shevchenko
2021-09-23  0:10 ` Linus Walleij

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.