diff mbox

pinctrl: phandle entries will be applied sequentially

Message ID 1381297324-19006-1-git-send-email-shawn.guo@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Shawn Guo Oct. 9, 2013, 5:42 a.m. UTC
It's naturally expected that when there are multiple phandle entries
specified in pinctrl-* property, these entries will be applied
sequentially.  And this is how Linux kernel works.  So let's define
this behavior in the binding doc.

The behavior is useful when people want to reuse a group of predefined
pins with only minor configuration adjustment on one particular pin.
They will only need to add another entry after the predefined one with
needed configuration on that particular pin to overwrite the predefined
configuration.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 .../bindings/pinctrl/pinctrl-bindings.txt          |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Comments

Linus Walleij Oct. 9, 2013, 12:40 p.m. UTC | #1
On Wed, Oct 9, 2013 at 7:42 AM, Shawn Guo <shawn.guo@linaro.org> wrote:

> It's naturally expected that when there are multiple phandle entries
> specified in pinctrl-* property, these entries will be applied
> sequentially.  And this is how Linux kernel works.  So let's define
> this behavior in the binding doc.

NAK this this a Linux kernel implementation detail. Sherman Yin
fixed this up so the drivers does not have to imply any sequence
semantic for this.

Study commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d
"pinctrl: Pass all configs to driver on pin_config_set()"

It is perfectly legal for a driver to accumulate the settings into
e.g. a single register write if it can, e.g.:

u32 val = 0;

for (i = 0; i < num_configs; i++) {
  switch() {
  FOO:
     val |= 1;
     break;
   BAR:
     val |= 2:
     break;
   BAZ:
     val |=4;
     break;
};

writel(val, base+pinreg);

I.e. the driver may choose to apply configs sequentially, but that is
not at all necessary.

Yours,
Linus Walleij
Russell King - ARM Linux Oct. 9, 2013, 12:44 p.m. UTC | #2
On Wed, Oct 09, 2013 at 02:40:49PM +0200, Linus Walleij wrote:
> NAK this this a Linux kernel implementation detail. Sherman Yin
> fixed this up so the drivers does not have to imply any sequence
> semantic for this.
> 
> Study commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d
> "pinctrl: Pass all configs to driver on pin_config_set()"
> 
> It is perfectly legal for a driver to accumulate the settings into
> e.g. a single register write if it can, e.g.:
> 
> u32 val = 0;
> 
> for (i = 0; i < num_configs; i++) {
>   switch() {
>   FOO:
>      val |= 1;
>      break;
>    BAR:
>      val |= 2:
>      break;
>    BAZ:
>      val |=4;
>      break;
> };
> 
> writel(val, base+pinreg);
> 
> I.e. the driver may choose to apply configs sequentially, but that is
> not at all necessary.

So, just to be clear, what you're saying is that specifying two settings
in a pinctrl declaration which provide different values results in
undefined behaviour?
Linus Walleij Oct. 9, 2013, 1:09 p.m. UTC | #3
On Wed, Oct 9, 2013 at 2:44 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Wed, Oct 09, 2013 at 02:40:49PM +0200, Linus Walleij wrote:

>> NAK this this a Linux kernel implementation detail. Sherman Yin
>> fixed this up so the drivers does not have to imply any sequence
>> semantic for this.
>>
>> Study commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d
>> "pinctrl: Pass all configs to driver on pin_config_set()"
>>
>> It is perfectly legal for a driver to accumulate the settings into
>> e.g. a single register write if it can, e.g.:
>>
>> u32 val = 0;
>>
>> for (i = 0; i < num_configs; i++) {
>>   switch() {
>>   FOO:
>>      val |= 1;
>>      break;
>>    BAR:
>>      val |= 2:
>>      break;
>>    BAZ:
>>      val |=4;
>>      break;
>> };
>>
>> writel(val, base+pinreg);
>>
>> I.e. the driver may choose to apply configs sequentially, but that is
>> not at all necessary.
>
> So, just to be clear, what you're saying is that specifying two settings
> in a pinctrl declaration which provide different values results in
> undefined behaviour?

It's more like the pin control core is passing the array of settings
to the driver and the behaviour is specified per-driver.

So that is from the kernels point of view, no matter whether
device tree is used or not. A specific driver may instill specific
behaviour - sequential or not.

Sherman's driver for the Broadcom Capri had the requirement that
the configuration of all parameters be done with a single register
write to avoid side-effects. So it needs to iterate the configs and
build up a mask and value and write it in one go.

When I look at the i.MX driver (I guess this is what Shawn
is working on here) it can actually be augmented to do it
the same way and avoid this mess altogether:

       for (i = 0; i < num_configs; i++) {
                if (info->flags & SHARE_MUX_CONF_REG) {
                        u32 reg;
                        reg = readl(ipctl->base + pin_reg->conf_reg);
                        reg &= ~0xffff;
                        reg |= configs[i];
                        writel(reg, ipctl->base + pin_reg->conf_reg);
                } else {
                        writel(configs[i], ipctl->base + pin_reg->conf_reg);
                }
                dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
                        pin_reg->conf_reg, configs[i]);
        } /* for each config */

As can be seen it will just writel() the config into the register
for each config, it seems more like there is a bug that also
the else-clause here should be read-modify-write, or am
I getting it all wrong?

In some cases some configs may be electrically conflicting
and completely unsound, like enabling pull-up and pull-down
at the same time - maybe possible in the hardware
but insane, so the driver should detect that state in this
loop and reject such configs, print a warning or make a
best effort.

I am aware that maybe not all drivers are handling this in
the most ultimate way today :-/

Then as this patch was against the device tree documentation:
since the device tree isn't really about sequencing things
(Grant has been onto us in the past for wanting to put sequences
in there) we should probably avoid defining such things as
sequences at all, as that basically moves the hardware
description toward a sequence description language (jam table),
and for that the full open firmware or other BIOS thing (ACPI?)
should be used instead. (If I understood the point correctly.)

I tend to think about the DT language as functional i.e. there
is no way to say anything about sequencing order from it,
I may be wrong here though.

Yours,
Linus Walleij
Russell King - ARM Linux Oct. 9, 2013, 1:45 p.m. UTC | #4
On Wed, Oct 09, 2013 at 03:09:21PM +0200, Linus Walleij wrote:
> It's more like the pin control core is passing the array of settings
> to the driver and the behaviour is specified per-driver.
> 
> So that is from the kernels point of view, no matter whether
> device tree is used or not. A specific driver may instill specific
> behaviour - sequential or not.

Right, so that means doing this:

                        pinctrl_usdhc1_1: usdhc1grp-1 {
                                fsl,pins = <
...
                                        MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
...
                                >;
                        };

                        pinctrl_usdhc1_1_dat3cd: usdhc1grp-3 {
                                fsl,pins = <
                                        MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x13059
                                >;
                        };

and then:

	pinctrl-0 = <&pinctrl_usdhc1_1 &pinctrl_usdhc1_1_dat3cd>;

can result in either "MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059" or
"MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x13059" being the final configuration
for that pin.

What that means is that for any pinctrl setting, pins to be configured
must be mentioned exactly once and once only.
Linus Walleij Oct. 9, 2013, 2:14 p.m. UTC | #5
On Wed, Oct 9, 2013 at 3:45 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:

> Right, so that means doing this:
>
>                         pinctrl_usdhc1_1: usdhc1grp-1 {
>                                 fsl,pins = <
> ...
>                                         MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
> ...
>                                 >;
>                         };
>
>                         pinctrl_usdhc1_1_dat3cd: usdhc1grp-3 {
>                                 fsl,pins = <
>                                         MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x13059
>                                 >;
>                         };
>
> and then:
>
>         pinctrl-0 = <&pinctrl_usdhc1_1 &pinctrl_usdhc1_1_dat3cd>;
>
> can result in either "MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059" or
> "MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x13059" being the final configuration
> for that pin.

I'm uncertain about the device tree case. I guess it is indeed
an array of handles indexed [0,1], the framework will only
send that array down to the driver, no strings attached.

> What that means is that for any pinctrl setting, pins to be configured
> must be mentioned exactly once and once only.

Either that (and the above does seem very ambigous) or the driver
need to combine and handle the conflicting configurations,
maintaining a state for the pin and so on ...

This seems like two *complete* configs fighting over the same pin
rather than two complementary configs that we could | together
and write, and that is indeed ambigous. The array passed to
the config function is supposed to be individual settings like
[ pull-up, schmitt-trigger ] not two complete sets of config.

The generic pin config binding is luckily  more clear than this
i.MX-specific handling.

Yours,
Linus Walleij
Stephen Warren Oct. 9, 2013, 3:58 p.m. UTC | #6
On 10/09/2013 06:44 AM, Russell King - ARM Linux wrote:
> On Wed, Oct 09, 2013 at 02:40:49PM +0200, Linus Walleij wrote:
>> NAK this this a Linux kernel implementation detail. Sherman Yin
>> fixed this up so the drivers does not have to imply any sequence
>> semantic for this.
>>
>> Study commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d
>> "pinctrl: Pass all configs to driver on pin_config_set()"
>>
>> It is perfectly legal for a driver to accumulate the settings into
>> e.g. a single register write if it can, e.g.:
>>
>> u32 val = 0;
>>
>> for (i = 0; i < num_configs; i++) {
>>   switch() {
>>   FOO:
>>      val |= 1;
>>      break;
>>    BAR:
>>      val |= 2:
>>      break;
>>    BAZ:
>>      val |=4;
>>      break;
>> };
>>
>> writel(val, base+pinreg);
>>
>> I.e. the driver may choose to apply configs sequentially, but that is
>> not at all necessary.
> 
> So, just to be clear, what you're saying is that specifying two settings
> in a pinctrl declaration which provide different values results in
> undefined behaviour?

That makes sense to me, yes. It should be simple to separate out the
common/shared parts of a configuration, vs. other unique parts, and put
them into separate "pin configuration nodes", and hence avoid the
situation completely.
Shawn Guo Oct. 10, 2013, 7:26 a.m. UTC | #7
On Wed, Oct 09, 2013 at 02:40:49PM +0200, Linus Walleij wrote:
> On Wed, Oct 9, 2013 at 7:42 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> 
> > It's naturally expected that when there are multiple phandle entries
> > specified in pinctrl-* property, these entries will be applied
> > sequentially.  And this is how Linux kernel works.  So let's define
> > this behavior in the binding doc.
> 
> NAK this this a Linux kernel implementation detail. Sherman Yin
> fixed this up so the drivers does not have to imply any sequence
> semantic for this.
> 
> Study commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d
> "pinctrl: Pass all configs to driver on pin_config_set()"
> 
> It is perfectly legal for a driver to accumulate the settings into
> e.g. a single register write if it can, e.g.:
> 
> u32 val = 0;
> 
> for (i = 0; i < num_configs; i++) {
>   switch() {
>   FOO:
>      val |= 1;
>      break;
>    BAR:
>      val |= 2:
>      break;
>    BAZ:
>      val |=4;
>      break;
> };
> 
> writel(val, base+pinreg);
> 
> I.e. the driver may choose to apply configs sequentially, but that is
> not at all necessary.

Yes, that's the case when pinconf_apply_setting() is called to apply a
struct pinctrl_setting.  This pinctrl_setting may contain multiple
configs (pull, drive, open drain etc.) for a pin, and driver may choose
to apply these configs sequentially or accumulatedly.  In case of device
tree, all these configs must be coming from a single pin configuration
node, as per my understanding of how pinctrl core code maps pin
configuration in device tree node to struct pinctrl_setting.

However, my patch is talking about a different thing.  For example, we
have a device whose pinctrl-0 consists of two phandle entries that point
to pin configuration nodes foo and bar.

	pinctrl-0 = <&foo &bar>;

	foo {
		...
	};

	bar {
		...
	};

My patch only wants to make it clear that the configuration specified by
node foo will be applied to pin controller first, and the configuration
defined in node bar will be applied after that.  When both nodes have
configuration for a pin, these two configs for the same pin go to two
different pinctrl_setting structures.  And these two pinctrl_settings
can not be applied accumulatedly but only sequentially.  That's what my
patch talks about.

Shawn
Linus Walleij Oct. 10, 2013, 8:03 a.m. UTC | #8
On Thu, Oct 10, 2013 at 9:26 AM, Shawn Guo <shawn.guo@linaro.org> wrote:

> However, my patch is talking about a different thing.  For example, we
> have a device whose pinctrl-0 consists of two phandle entries that point
> to pin configuration nodes foo and bar.
>
>         pinctrl-0 = <&foo &bar>;
>
>         foo {
>                 ...
>         };
>
>         bar {
>                 ...
>         };
>
> My patch only wants to make it clear that the configuration specified by
> node foo will be applied to pin controller first, and the configuration
> defined in node bar will be applied after that.  When both nodes have
> configuration for a pin, these two configs for the same pin go to two
> different pinctrl_setting structures.  And these two pinctrl_settings
> can not be applied accumulatedly but only sequentially.  That's what my
> patch talks about.

OK I get it (I think).

However isn't this aspect rather a property of how the specific driver
parses and uses the device tree?

Remember that with drivers that do not use generic pin config,
we have left the handling of the device tree node up to the driver
by the callback dt_node_to_map().

But I do understand the ambition to specify this behaviour for all
pin control drivers using device tree.

But we need to be careful since DT isn't very much in the
buisiness of defining sequence semantics for stuff, and that
is why I'm a bit hesitant.

So, maybe we can add this as it only concerns the binding
(but then I want that example to be part of the documentation patch
so that it is crystal clear what we're talking about), but it would be
proper if we also helped enforce this semantic across the drivers,
i.e. centralize more of the DT parsing code...

BTW on a related subject: have you examined if the i.MX driver
can use the new utility functions from pinctrl-utils.h:

pinctrl_utils_reserve_map()
pinctrl_utils_add_map_mux()
pinctrl_utils_add_map_configs()
pinctrl_utils_add_config()
pinctrl_utils_dt_free_map()

It helps a lot the more boilerplate we can move out of the
drivers and get a clear picture of the device tree parsing code,
and see what really needs to be different across the drivers.

Yours,
Linus Walleij
Shawn Guo Oct. 10, 2013, 8:08 a.m. UTC | #9
On Wed, Oct 09, 2013 at 03:09:21PM +0200, Linus Walleij wrote:
> When I look at the i.MX driver (I guess this is what Shawn
> is working on here) it can actually be augmented to do it
> the same way and avoid this mess altogether:
> 
>        for (i = 0; i < num_configs; i++) {
>                 if (info->flags & SHARE_MUX_CONF_REG) {
>                         u32 reg;
>                         reg = readl(ipctl->base + pin_reg->conf_reg);
>                         reg &= ~0xffff;
>                         reg |= configs[i];
>                         writel(reg, ipctl->base + pin_reg->conf_reg);
>                 } else {
>                         writel(configs[i], ipctl->base + pin_reg->conf_reg);
>                 }
>                 dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
>                         pin_reg->conf_reg, configs[i]);
>         } /* for each config */
> 
> As can be seen it will just writel() the config into the register
> for each config, it seems more like there is a bug that also
> the else-clause here should be read-modify-write, or am
> I getting it all wrong?

On imx, num_configs is always 1 (new_map[j].data.configs.num_configs
is hard-coded as 1 in imx_dt_node_to_map() function).  We have all
configs for given pin encoded in the last integer of fsl,pin entry.
And this integer can be directly written into conf_reg.

Shawn
Russell King - ARM Linux Oct. 10, 2013, 10:08 a.m. UTC | #10
On Thu, Oct 10, 2013 at 03:26:26PM +0800, Shawn Guo wrote:
> However, my patch is talking about a different thing.  For example, we
> have a device whose pinctrl-0 consists of two phandle entries that point
> to pin configuration nodes foo and bar.
> 
> 	pinctrl-0 = <&foo &bar>;
> 
> 	foo {
> 		...
> 	};
> 
> 	bar {
> 		...
> 	};
> 
> My patch only wants to make it clear that the configuration specified by
> node foo will be applied to pin controller first, and the configuration
> defined in node bar will be applied after that.  When both nodes have
> configuration for a pin, these two configs for the same pin go to two
> different pinctrl_setting structures.  And these two pinctrl_settings
> can not be applied accumulatedly but only sequentially.  That's what my
> patch talks about.

I still say this is a potentially dangerous thing, and in my case of
overriding the DAT3 pull-sense, it will cause the pin to glitch if
nothing is connected to it.

So even if you do get this clarified, I am *not* happy to change my
patch.
Shawn Guo Oct. 10, 2013, 10:12 a.m. UTC | #11
On Thu, Oct 10, 2013 at 10:03:40AM +0200, Linus Walleij wrote:
> On Thu, Oct 10, 2013 at 9:26 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> 
> > However, my patch is talking about a different thing.  For example, we
> > have a device whose pinctrl-0 consists of two phandle entries that point
> > to pin configuration nodes foo and bar.
> >
> >         pinctrl-0 = <&foo &bar>;
> >
> >         foo {
> >                 ...
> >         };
> >
> >         bar {
> >                 ...
> >         };
> >
> > My patch only wants to make it clear that the configuration specified by
> > node foo will be applied to pin controller first, and the configuration
> > defined in node bar will be applied after that.  When both nodes have
> > configuration for a pin, these two configs for the same pin go to two
> > different pinctrl_setting structures.  And these two pinctrl_settings
> > can not be applied accumulatedly but only sequentially.  That's what my
> > patch talks about.
> 
> OK I get it (I think).
> 
> However isn't this aspect rather a property of how the specific driver
> parses and uses the device tree?

The 'pinctrl-0' property is defined by common pinctrl device tree
binding and is parsed by pinctrl core, while pin configuration node
is platform specific and handled by controller driver.

> Remember that with drivers that do not use generic pin config,
> we have left the handling of the device tree node up to the driver
> by the callback dt_node_to_map().

Yes.  dt_node_to_map() takes pin configuration node pointer as input and
return a set of struct pinctrl_map.  But how pinctrl_map eventually gets
turned into pinctrl_setting as the input to pinconf_apply_setting() call
are all handled by pinctrl core and common across different controller
drivers.

> But I do understand the ambition to specify this behaviour for all
> pin control drivers using device tree.
> 
> But we need to be careful since DT isn't very much in the
> buisiness of defining sequence semantics for stuff, and that
> is why I'm a bit hesitant.
> 
> So, maybe we can add this as it only concerns the binding
> (but then I want that example to be part of the documentation patch
> so that it is crystal clear what we're talking about), but it would be
> proper if we also helped enforce this semantic across the drivers,
> i.e. centralize more of the DT parsing code...

Ok.  I would hold it off for a while and consider Stephen's comment
first for solving the problem we have on i.MX.

> BTW on a related subject: have you examined if the i.MX driver
> can use the new utility functions from pinctrl-utils.h:
> 
> pinctrl_utils_reserve_map()
> pinctrl_utils_add_map_mux()
> pinctrl_utils_add_map_configs()
> pinctrl_utils_add_config()
> pinctrl_utils_dt_free_map()

Thanks for the info.  Just had a quick look at them, and it seems that
they don't save too much code for imx.  Will take another deep look
though.

Shawn
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
index 1958ca9..404ba32 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -50,7 +50,13 @@  pinctrl-0:	List of phandles, each pointing at a pin configuration
 		entries may exist in this list so that multiple pin
 		controllers may be configured, or so that a state may be built
 		from multiple nodes for a single pin controller, each
-		contributing part of the overall configuration. See the next
+		contributing part of the overall configuration. These entries
+		will be applied sequentially. If there are multiple entries
+		contributing the configuration of the same pin, the latter
+		will overwrite the former. However, this 'overwrite' mechanism
+		should be used with the caution that it could cause some ill
+		effect, e.g. a glitch on the pin when pull down/up setting
+		gets flipped in this 'overwrite'.  See the next
 		section of this document for details of the format of these
 		pin configuration nodes.