Skip to contentSkip to conversation

PowerPC: implement support for GPIO LIB API

RFC PATCH In review Anton Vorontsov 5 participants 10 messages Jan 8, 2008 – Jan 27, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover PowerPC: implement support for GPIO LIB API

Hi all,

Thanks for the previous review and ideas. Here is the RFC for the GPIO LIB support.

I'm using it like this:

	qe_pio_a: gpio-controller@1400 {
		#gpio-cells = <1>;
		compatible = "fsl,qe-pario-bank";
		reg = <0x1400 0x18>;
		gpio-controller;
	};

	qe_pio_e: gpio-controller@1460 {
		#gpio-cells = <1>;
		compatible = "fsl,qe-pario-bank";
		reg = <0x1460 0x18>;
		gpio-controller;
	};

	nand-flash@1,0 {
		compatible = "stmicro,NAND512W3A2BN6E", "fsl,upm-nand";
		reg = <1 0 1>;
		width = <1>;
		upm = "A";
		upm-addr-offset = <16>;
		upm-cmd-offset = <8>;
		gpios = <&qe_pio_e 18 &qe_pio_a 9>;
		wait-pattern;
		wait-write;
	};

As you can see I've split single "par_io" node into banks, thus the benefits:
- we can handle banks of different width (Jochen Friedrich asked for this, IIRC. Or I've misunderstood ;-).
- we can handle banks with different paddings (no more #ifdef PPC85xx).

Also, it's possible to specify different gpio-controllers in the gpios = <> property. gpio-specifier is controller specific.

The remaining question is about gpio.c placement. prom_parse.c doesn't feel as the appropriate place anymore. I think of:

- drivers/gpio/of_gpio.c (driver/gpio/ is in -mm tree);
- drivers/of/gpio.c
- keep it in arch/powerpc/kernel/ (though, there is nothing much PowerPC specific).

So, to try these patches you'll need apply these from the -mm tree:
generic-gpio-gpio_chip-support.patch generic-gpio-gpio_chip-support-fix.patch generic-gpio-gpio_chip-support-gpiolib-locking-simplified.patch

Or just issue this in your working tree:

git pull git://git.infradead.org/users/cbou/powerpc-gpio.git gpiolib

powerpc-gpio.git's gpiolib branch is galak/powerpc.git master branch + -mm patches + these patches.

Support for CPM2 is pending.

Thanks!

Signature · 4 lines
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2
#1 lore raw

PATCH 1/3 Implement support for the GPIO LIB API

This patch implements support for the GPIO LIB API. Two calls unimplemented though: irq_to_gpio and gpio_to_irq.

Various OF helpers provided to ease life and reduce code duplication.

---
 Documentation/powerpc/booting-without-of.txt |   58 ++++++++
 arch/powerpc/Kconfig                         |    5 +
 arch/powerpc/kernel/Makefile                 |    1 +
 arch/powerpc/kernel/gpio.c                   |  186 ++++++++++++++++++++++++++
 include/asm-powerpc/gpio.h                   |  126 +++++++++++++++++
 5 files changed, 376 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/kernel/gpio.c
 create mode 100644 include/asm-powerpc/gpio.h
Documentation/powerpc/booting-without-of.txt +58 -0
index ee0209a..dd2613c 100644
@@ -60,6 +60,10 @@ Table of Contents
     3) OpenPIC Interrupt Controllers
     4) ISA Interrupt Controllers
 
+  VIII - Specifying GPIO information for devices
+    1) gpios property
+    2) gpio-controller nodes
+
   Appendix A - Sample SOC node for MPC8540
 
 
@@ -2618,6 +2622,60 @@ encodings listed below:
 	2 =  high to low edge sensitive type enabled
 	3 =  low to high edge sensitive type enabled
 
+VIII - Specifying GPIO information for devices
+==============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+		     &gpio-controller2-phandle gpio2-specifier
+		     ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is active-low.
+
+Example of the node using GPIOs:
+
+	nand-flash@1,0 {
+		compatible = "stmicro,NAND512W3A2BN6E", "fsl,upm-nand";
+		reg = <1 0 1>;
+		width = <1>;
+		upm = "A";
+		upm-addr-offset = <16>;
+		upm-cmd-offset = <8>;
+		gpios = <&qe_pio_e 18>;
+		wait-pattern;
+		wait-write;
+	};
+
+In that example gpio-specifier is "18" and encodes GPIO pin number only,
+as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+	qe_pio_a: gpio-controller@1400 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1400 0x18>;
+		gpio-controller;
+	};
+
+	qe_pio_e: gpio-controller@1460 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1460 0x18>;
+		gpio-controller;
+	};
 
 Appendix A - Sample SOC node for MPC8540
 ========================================
arch/powerpc/Kconfig +5 -0
index 66a3d8c..b38c84a 100644
@@ -73,6 +73,11 @@ config GENERIC_FIND_NEXT_BIT
 	bool
 	default y
 
+config GENERIC_GPIO
+	bool
+	help
+	  Generic GPIO API support
+
 config ARCH_NO_VIRT_TO_BUS
 	def_bool PPC64
 
arch/powerpc/kernel/Makefile +1 -0
index 9374bc9..943045c 100644
@@ -65,6 +65,7 @@ obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
+obj-$(CONFIG_GPIO_LIB)		+= gpio.o
 
 pci64-$(CONFIG_PPC64)		+= pci_dn.o isa-bridge.o
 obj-$(CONFIG_PCI)		+= pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
arch/powerpc/kernel/gpio.c new file +186 -0

186 lines not on this page · raw message

include/asm-powerpc/gpio.h new file +126 -0

126 lines not on this page · raw message

Signature · 1 line
1.5.2.2
#2 lore raw

Re: [PATCH 1/3] [POWERPC] Implement support for the GPIO LIB API

Quoted 15 lines · On Tue, 8 Jan 2008 21:45:18 +0300 Anton Vorontsov <[email protected]>…
arch/powerpc/kernel/gpio.c new file +14 -0
+int of_mm_gpiochip_add(struct device_node *np,
+		       const struct of_gpio_chip *of_gc)
+{
+	int ret = -ENOMEM;
+	struct of_mm_gpio_chip *mm_gc;
+
+	mm_gc = kzalloc(sizeof(*mm_gc), GFP_KERNEL);
+	if (!mm_gc)
+		goto err0;
+
+	mm_gc->of_gc = *of_gc;
+
+	mm_gc->of_gc.gc.label = kstrdup(np->full_name, GFP_KERNEL);
+	if (!mm_gc->of_gc.gc.label)

arch/powerpc/kernel/gpio.c line 160

Quoted 10 lines
arch/powerpc/kernel/gpio.c new file +10 -0
+		goto err1;
+
+	ret = of_get_gpiochip_base(np);
+	if (ret < 0)
+		goto err2;
+
+	mm_gc->regs = of_iomap(np, 0);
+	if (!mm_gc->regs) {
+		ret = -ENOMEM;
+		goto err1;

Should this be err2?

arch/powerpc/kernel/gpio.c line 171

Quoted 11 lines
arch/powerpc/kernel/gpio.c new file +11 -0
+	}
+
+	mm_gc->of_gc.gc.base = ret;
+
+	np->data = &mm_gc->of_gc;
+
+	ret = gpiochip_add(&mm_gc->of_gc.gc);
+	if (ret)
+		goto err2;
+
+	of_node_get(np);

Why do you this of_node_get(np) when you do not keep a reference to np in this routine?

Signature · 3 lines
Cheers,
Stephen Rothwell                    [email protected]
http://www.canb.auug.org.au/~sfr/
#3 lore raw

PATCH 2/3 QE: split par_io_config_pin()

In reply to Anton Vorontsov

This patch splits par_io_config_pin so we can use it with GPIO LIB API.

Also add a comment regarding #ifdef CONFIG_PPC_85xx being legacy.

---
 arch/powerpc/sysdev/qe_lib/qe_io.c |   60 +++++++++++++++++++++++------------
 1 files changed, 39 insertions(+), 21 deletions(-)
arch/powerpc/sysdev/qe_lib/qe_io.c +39 -21
index e53ea4d..aef893b 100644
@@ -37,6 +37,10 @@ struct port_regs {
 	__be32	cppar1;		/* Pin assignment register */
 	__be32	cppar2;		/* Pin assignment register */
 #ifdef CONFIG_PPC_85xx
+	/*
+	 * This is needed for legacy support only, should go away,
+	 * because we started using per-bank gpio chips.
+	 */
 	u8	pad[8];
 #endif
 };
@@ -63,28 +67,29 @@ int par_io_init(struct device_node *np)
 	return 0;
 }
 
-int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
-		      int assignment, int has_irq)
+static void __par_io_config_pin(struct port_regs __iomem *par_io,
+				u8 pin, int dir, int open_drain,
+				int assignment, int has_irq)
 {
-	u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
-
-	if (!par_io)
-		return -1;
+	u32 pin_mask1bit;
+	u32 pin_mask2bits;
+	u32 new_mask2bits;
+	u32 tmp_val;
 
 	/* calculate pin location for single and 2 bits information */
 	pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
 
 	/* Set open drain, if required */
-	tmp_val = in_be32(&par_io[port].cpodr);
+	tmp_val = in_be32(&par_io->cpodr);
 	if (open_drain)
-		out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
+		out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
 	else
-		out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
+		out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
 
 	/* define direction */
 	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
-		in_be32(&par_io[port].cpdir2) :
-		in_be32(&par_io[port].cpdir1);
+		in_be32(&par_io->cpdir2) :
+		in_be32(&par_io->cpdir1);
 
 	/* get all bits mask for 2 bit per port */
 	pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
@@ -96,36 +101,49 @@ int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
 
 	/* clear and set 2 bits mask */
 	if (pin > (NUM_OF_PINS / 2) - 1) {
-		out_be32(&par_io[port].cpdir2,
+		out_be32(&par_io->cpdir2,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
+		out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
 	} else {
-		out_be32(&par_io[port].cpdir1,
+		out_be32(&par_io->cpdir1,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
+		out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
 	}
 	/* define pin assignment */
 	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
-		in_be32(&par_io[port].cppar2) :
-		in_be32(&par_io[port].cppar1);
+		in_be32(&par_io->cppar2) :
+		in_be32(&par_io->cppar1);
 
 	new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
 			(pin % (NUM_OF_PINS / 2) + 1) * 2));
 	/* clear and set 2 bits mask */
 	if (pin > (NUM_OF_PINS / 2) - 1) {
-		out_be32(&par_io[port].cppar2,
+		out_be32(&par_io->cppar2,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
+		out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
 	} else {
-		out_be32(&par_io[port].cppar1,
+		out_be32(&par_io->cppar1,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
+		out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
 	}
+}
+
+/*
+ * This is "legacy" function that takes port number as an argument
+ * instead of pointer to the appropriate bank.
+ */
+int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+		      int assignment, int has_irq)
+{
+	if (!par_io || port >= num_par_io_ports)
+		return -EINVAL;
 
+	__par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment,
+			    has_irq);
 	return 0;
 }
 EXPORT_SYMBOL(par_io_config_pin);
Signature · 1 line
1.5.2.2
#4 lore raw

PATCH 3/3 QE: implement GPIO LIB API

In reply to Anton Vorontsov
---
 Documentation/powerpc/booting-without-of.txt |   32 +++++++----
 arch/powerpc/platforms/Kconfig               |    2 +
 arch/powerpc/sysdev/qe_lib/qe_io.c           |   73 ++++++++++++++++++++++++++
 include/asm-powerpc/qe.h                     |    1 +
 4 files changed, 96 insertions(+), 12 deletions(-)
Documentation/powerpc/booting-without-of.txt +20 -12
index dd2613c..e279152 100644
@@ -1696,24 +1696,32 @@ platforms are moved over to use the flattened-device-tree model.
    information.
 
    Required properties:
-   - device_type : should be "par_io".
+   - #gpio-cells : should be "1".
+   - compatible : should be "fsl,qe-pario-bank"
    - reg : offset to the register set and its length.
-   - num-ports : number of Parallel I/O ports
+   - gpio-controller : node to identify gpio controllers.
 
-   Example:
-	par_io@1400 {
-		reg = <1400 100>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		device_type = "par_io";
-		num-ports = <7>;
-		ucc_pin@01 {
-			......
-		};
+   For example, two QE Par I/O banks:
+	qe_pio_a: gpio-controller@1400 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1400 0x18>;
+		gpio-controller;
+	};
 
+	qe_pio_e: gpio-controller@1460 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1460 0x18>;
+		gpio-controller;
+	};
 
    vi) Pin configuration nodes
 
+   NOTE: pin configuration nodes are obsolete. Usually, their existance
+         is an evidence of the firmware shortcomings. Such fixups are
+         better handled by the Linux board file, not the device tree.
+
    Required properties:
    - linux,phandle : phandle of this node; likely referenced by a QE
      device.
arch/powerpc/platforms/Kconfig +2 -0
index ea22cad..8dff946 100644
@@ -265,6 +265,8 @@ config TAU_AVERAGE
 config QUICC_ENGINE
 	bool
 	select PPC_LIB_RHEAP
+	select GENERIC_GPIO
+	select GPIO_LIB
 	help
 	  The QUICC Engine (QE) is a new generation of communications
 	  coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
arch/powerpc/sysdev/qe_lib/qe_io.c +73 -0

85 lines not on this page · raw message

include/asm-powerpc/qe.h +1 -0
index a24b7b1..2efda82 100644
@@ -77,6 +77,7 @@ enum qe_clock {
 /* Export QE common operations */
 extern void qe_reset(void);
 extern int par_io_init(struct device_node *np);
+extern int qe_gpiochip_add(struct device_node *np);
 extern int par_io_of_config(struct device_node *np);
 extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
 			     int assignment, int has_irq);
Signature · 1 line
1.5.2.2
#5 lore raw

Re: [PATCH 3/3] [POWERPC] QE: implement GPIO LIB API

Hi Anton,

Quoted 7 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +7 -0
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct port_regs *regs = mm_gc->regs;
+	u32 pin_mask;
+	u32 tmp_val;
+

arch/powerpc/sysdev/qe_lib/qe_io.c int par_io_of_config(struct device_node *np) · line 249

Quoted 10 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +10 -0
+	/* calculate pin location */
+	pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+	tmp_val = in_be32(&regs->cpdata);
+
+	if (val == 0)
+		out_be32(&regs->cpdata, ~pin_mask & tmp_val);
+	else
+		out_be32(&regs->cpdata, pin_mask | tmp_val);
+}

I see a possible problem with this (and in the corresponding call in CPM1, as well):

if there is a pin configured as open drain, you might accidently switch this pin to 0 while switching a different pin, if an external device is pulling the pin to 0.

i2c-gpio.c and w1-gpio.c (in -mm) are examples of drivers which use open drain pins and which would fail if another pin on the same port would be set during a transfer.

Thanks,
Jochen

#6 lore raw

Re: [PATCH 3/3] [POWERPC] QE: implement GPIO LIB API

Quoted 22 lines · Jochen Friedrich

Hi Anton,

Quoted 7 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +7 -0
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct port_regs *regs = mm_gc->regs;
+	u32 pin_mask;
+	u32 tmp_val;
+

arch/powerpc/sysdev/qe_lib/qe_io.c int par_io_of_config(struct device_node *np) · line 249

Quoted 10 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +10 -0
+	/* calculate pin location */
+	pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+	tmp_val = in_be32(&regs->cpdata);
+
+	if (val == 0)
+		out_be32(&regs->cpdata, ~pin_mask & tmp_val);
+	else
+		out_be32(&regs->cpdata, pin_mask | tmp_val);
+}

I see a possible problem with this (and in the corresponding call in CPM1, as well):

Quoted 2 lines

if there is a pin configured as open drain, you might accidently switch this pin to 0 while switching a different pin, if an external device is pulling the pin to 0.

Unfortunately I can't think out any workaround for this, except implementing generic gpio_bank_{,un}lock(gpio_pin_on_the_bank), and start using it in the drivers that might care about this issue. Though, looking into i2c-gpio.c I don't clearly see were we can insert these locks, there should be "start/end transaction" handlers or something, but it seems that it's in the bitbanging code, not in the i2c-gpio driver..

Actually, I see this as a hardware limitation. For example, on ARMs PXA2xx, there are separate, per bank, read/set/clear GPIO registers, not all-in-one data register.

Signature · 4 lines
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2
#7 lore raw

Re: [PATCH 3/3] [POWERPC] QE: implement GPIO LIB API

Quoted 34 lines · Anton Vorontsov
Quoted 22 lines · Jochen Friedrich

Hi Anton,

Quoted 7 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +7 -0
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+   struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+   struct port_regs *regs = mm_gc->regs;
+   u32 pin_mask;
+   u32 tmp_val;
+

arch/powerpc/sysdev/qe_lib/qe_io.c int par_io_of_config(struct device_node *np) · line 249

Quoted 10 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +10 -0
+   /* calculate pin location */
+   pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+   tmp_val = in_be32(&regs->cpdata);
+
+   if (val == 0)
+           out_be32(&regs->cpdata, ~pin_mask & tmp_val);
+   else
+           out_be32(&regs->cpdata, pin_mask | tmp_val);
+}

I see a possible problem with this (and in the corresponding call in CPM1, as well):

Quoted 2 lines

if there is a pin configured as open drain, you might accidently switch this pin to 0 while switching a different pin, if an external device is pulling the pin to 0.

Unfortunately I can't think out any workaround for this, except implementing generic gpio_bank_{,un}lock(gpio_pin_on_the_bank), and start using it in the drivers that might care about this issue. Though, looking into i2c-gpio.c I don't clearly see were we can insert these locks, there should be "start/end transaction" handlers or something, but it seems that it's in the bitbanging code, not in the i2c-gpio driver..

Quoted 3 lines

Actually, I see this as a hardware limitation. For example, on ARMs PXA2xx, there are separate, per bank, read/set/clear GPIO registers, not all-in-one data register.

I've run into this exact issue on other GPIO hardware too. It's not uncommon behaviour in GPIO hardware.

The solution is to not depend on the hardware to remember what the output pin values should be. Add a shadow register in the driver private data. Set the pin state for each output pin in the shadow register and then write that value to the hardware. That way input state doesn't interfere with the output values.

Also, you do still need spinlocks around the manipulation of the shared registers; otherwise you'll have very hard to debug race conditions. Probably one spin lock per bank.

Here's what I did for a Xilinx GPIO block driver (but ignore the fact that I'm not using driver private data so only one GPIO block can be supported; that will be fixed before I post this driver)

+void gpio_set_value(unsigned gpio, int value)
+{
+ unsigned long flags;
+
+ if (!gpio_regs)
+ return;
+
+ spin_lock_irqsave(&gpio_spinlock, flags);
+ if (value)
+ gpio_output_state |= 1<<gpio;
+ else
+ gpio_output_state &= ~(1<<gpio);
+ out_be32(gpio_regs, gpio_output_state);
+ spin_unlock_irqrestore(&gpio_spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(gpio_set_value);

Cheers,
g.

Quoted 11 lines

--
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2
_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Signature · 2 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
#8 lore raw

Re: [PATCH 3/3] [POWERPC] QE: implement GPIO LIB API

Quoted 38 lines · Anton Vorontsov
Quoted 34 lines · Jochen Friedrich
Quoted 22 lines

Hi Anton,

Quoted 7 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +7 -0
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+   struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+   struct port_regs *regs = mm_gc->regs;
+   u32 pin_mask;
+   u32 tmp_val;
+

arch/powerpc/sysdev/qe_lib/qe_io.c int par_io_of_config(struct device_node *np) · line 249

Quoted 10 lines
arch/powerpc/sysdev/qe_lib/qe_io.c +10 -0
+   /* calculate pin location */
+   pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+   tmp_val = in_be32(&regs->cpdata);
+
+   if (val == 0)
+           out_be32(&regs->cpdata, ~pin_mask & tmp_val);
+   else
+           out_be32(&regs->cpdata, pin_mask | tmp_val);
+}

I see a possible problem with this (and in the corresponding call in CPM1, as well):

Quoted 2 lines

if there is a pin configured as open drain, you might accidently switch this pin to 0 while switching a different pin, if an external device is pulling the pin to 0.

Unfortunately I can't think out any workaround for this, except implementing generic gpio_bank_{,un}lock(gpio_pin_on_the_bank), and start using it in the drivers that might care about this issue. Though, looking into i2c-gpio.c I don't clearly see were we can insert these locks, there should be "start/end transaction" handlers or something, but it seems that it's in the bitbanging code, not in the i2c-gpio driver..

Quoted 3 lines

Actually, I see this as a hardware limitation. For example, on ARMs PXA2xx, there are separate, per bank, read/set/clear GPIO registers, not all-in-one data register.

Quoted 8 lines

I've run into this exact issue on other GPIO hardware too. It's not uncommon behaviour in GPIO hardware.

The solution is to not depend on the hardware to remember what the output pin values should be. Add a shadow register in the driver private data. Set the pin state for each output pin in the shadow register and then write that value to the hardware. That way input state doesn't interfere with the output values.

Great idea, much thanks. Would be easy to implement also.

Quoted 3 lines

Also, you do still need spinlocks around the manipulation of the shared registers; otherwise you'll have very hard to debug race conditions. Probably one spin lock per bank.

With GPIO LIB we already have per bank spinlock, so it isn't a problem.

Thanks,

Signature · 4 lines
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2
#9 lore raw
In reply to Anton Vorontsov
Quoted 4 lines · Anton Vorontsov

Hi all,

Thanks for the previous review and ideas. Here is the RFC for the GPIO LIB support.

I like this layout for gpios. It's concise and compact. It will work well for my gpio driver also.

Quoted 6 lines

I'm using it like this:

        qe_pio_a: gpio-controller@1400 {
                #gpio-cells = <1>;
                compatible = "fsl,qe-pario-bank";

Here's my only comment: Compatible should have "fsl,<chip>-pario-bank" first. Be specific for the first value of the compatible property. You can add generic names after the specific one if you like, but it's hard to come up with a generic name when you don't know what a manufacture is going to do with it's marketing names in the future.

Quoted 66 lines
                reg = <0x1400 0x18>;
                gpio-controller;
        };

        qe_pio_e: gpio-controller@1460 {
                #gpio-cells = <1>;
                compatible = "fsl,qe-pario-bank";
                reg = <0x1460 0x18>;
                gpio-controller;
        };

        nand-flash@1,0 {
                compatible = "stmicro,NAND512W3A2BN6E", "fsl,upm-nand";
                reg = <1 0 1>;
                width = <1>;
                upm = "A";
                upm-addr-offset = <16>;
                upm-cmd-offset = <8>;
                gpios = <&qe_pio_e 18 &qe_pio_a 9>;
                wait-pattern;
                wait-write;
        };

As you can see I've split single "par_io" node into banks, thus the benefits:
- we can handle banks of different width (Jochen Friedrich asked for this, IIRC. Or I've misunderstood ;-).
- we can handle banks with different paddings (no more #ifdef PPC85xx).

Also, it's possible to specify different gpio-controllers in the gpios = <> property. gpio-specifier is controller specific.

The remaining question is about gpio.c placement. prom_parse.c doesn't feel as the appropriate place anymore. I think of:

- drivers/gpio/of_gpio.c (driver/gpio/ is in -mm tree);
- drivers/of/gpio.c
- keep it in arch/powerpc/kernel/ (though, there is nothing much PowerPC specific).

So, to try these patches you'll need apply these from the -mm tree:
generic-gpio-gpio_chip-support.patch generic-gpio-gpio_chip-support-fix.patch generic-gpio-gpio_chip-support-gpiolib-locking-simplified.patch

Or just issue this in your working tree:

git pull git://git.infradead.org/users/cbou/powerpc-gpio.git gpiolib

powerpc-gpio.git's gpiolib branch is galak/powerpc.git master branch + -mm patches + these patches.

Support for CPM2 is pending.

Thanks!

--
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2

Signature · 2 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.