Skip to content

Conversation

@erwango
Copy link
Member

@erwango erwango commented May 3, 2019

gpio-map is defined in dts v0.3 as "nexus node".
It allows to describe a pin connector so it can be referenced
through phandles and hence used in expansion device nodes
(typically implemented through overlays).

This change implements gpio controller resolution through these maps.
Few assumptions were taken in order to simplify the implementation.
These assumptions enforce some limitations to the use of gpio-map
but my understanding is that this should still allow to cover most
use cases.

Assumptions:
-gpio-size is the same for all gpio-controllers referenced in a map
-optional properties gpio-map-mask and gpio-map-pass-thru are
supposed to be omitted
The understanding of this last assumption is that flags provided in
the expansion device node will overwrite the connector flags

Fixes #15637

Signed-off-by: Erwan Gouriou [email protected]

@erwango erwango added area: Devicetree DNM This PR should not be merged (Do Not Merge) area: Shields Shields (add-on boards) labels May 3, 2019
@erwango erwango requested review from galak, mike-scott and ulfalizer May 3, 2019 14:48
@erwango
Copy link
Member Author

erwango commented May 3, 2019

@mike-scott, I had a try on a (former) modified version of your PR and it worked. Can you have a try when you have some time?

EDIT: Here is a branch making it working on top of #14057. Remaining detail is the change of a _0 to _1. Otherwise it, at least, compiles. I haven't been able to test though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oversight, txs!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using .get('gpio-map') instead of ['gpio-map'] here isn't safer, because if raw_map ever ends up as None, then len(raw_map) below will crash.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so using ['gpio-map'], then.
This should not end up as None since function is called only if gpio-map in reduced....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here, re. .get() vs. [].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here, re. .get() vs. [].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

Copy link
Contributor

@ulfalizer ulfalizer May 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bare try: ... except: is usually a bad idea, because it will hide stuff like references to undefined Python variables as well (those throw exceptions).

Catch Exception instead, or (better) do a more explicit check for whatever this is checking, without using exceptions.

Copy link
Member Author

@erwango erwango May 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, so actually this is the result of a late refactoring and this not chacking anything good anymore. Let me rework that.
EDIT: Actually it was catching stuff, but edited wrt your review

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here.

@erwango
Copy link
Member Author

erwango commented May 6, 2019

@ulfalizer, thanks for the review. Updated.

@erwango erwango requested a review from ulfalizer May 6, 2019 12:46
@erwango erwango removed the DNM This PR should not be merged (Do Not Merge) label May 6, 2019
Copy link
Contributor

@ulfalizer ulfalizer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think the function could have some x_to_y()-like name btw, so you can tell from the name what it maps to what? From the current name, you can only tell that it's doing some kind of mapping somehow related to GPIO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the : mean that cell_parent is a gpio-map? Might be clearer to write it out in that case ("cell_parent, which is a gpio-map").

"From the object provided" is a bit confusing since the function takes two arguments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two are only used at the end of the function. Might be clearer to move them there, right before where they're used.

Then the documentation for the function ends up at the top too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe gpio_map_lookup() could return None or something instead if the controller isn't found. Reading this quickly, you wonder if the IndexError is there to guard the elem[1] lookup or the like.

Exceptions for control flow often gets confusing.

Copy link
Member Author

@erwango erwango May 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I reworked a bit, I'm not finding that much better in terms of exception, but seems more coherent in the dt object type handling. Let me know.

@erwango erwango requested a review from ulfalizer May 6, 2019 15:29
@mike-scott
Copy link
Contributor

@mike-scott, I had a try on a (former) modified version of your PR and it worked. Can you have a try when you have some time?

EDIT: Here is a branch making it working on top of #14057. Remaining detail is the change of a _0 to _1. Otherwise it, at least, compiles. I haven't been able to test though.

Absolutely. Thank you for working on this. I'll respond back once I kick the tires a bit and look through this.

@mike-scott
Copy link
Contributor

@erwango Actually, I don't see the branch based on the shield changes? Did I miss a link?

@erwango
Copy link
Member Author

erwango commented May 6, 2019

@mike-scott, you didn't miss anything, I omited the paste operation. Here it is: https://github.com/erwango/zephyr/tree/test_14057_gpio_map

EDIT: It does not contain the last changes of current PR, but this should not change the global behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could reflow this paragraph so that the lines are about the same length (with e.g. gq in Vim).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidental period in the middle of the sentence?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't immediately tell which of the [gpio_index], [child_specifier_size], and [controller_phandle] lookups are meant to be able to generate the IndexError under "normal" operation of the program here.

Better to do something like this, and avoid try/except completely:

if gpio_index not in map_array:
    return None

...

That makes the intention clear, and means that errors in the code won't be eaten by the except IndexError:.

Copy link
Contributor

@ulfalizer ulfalizer May 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be is not None, not is not 'None'. Just if not gpio_controller: should work though.

Something like this:

if not gpio_controller:
    raise Exception("GPIO controller not found")
cell_parent = gpio_controller

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here.

@mike-scott
Copy link
Contributor

@erwango I tested this tonight and noticed that the values for the PINs was the index of the gpio-map used (example is for Sara R4 modem -- see header pins 12 and 11):

		mdm-reset-gpios = <&arduino_header 12 0>;
		mdm-power-gpios = <&arduino_header 11 0>;

Example:

#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_POWER_GPIOS_CONTROLLER		"GPIO_0"
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_POWER_GPIOS_FLAGS		0
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_POWER_GPIOS_PIN			11
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_RESET_GPIOS_CONTROLLER		"GPIO_2"
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_RESET_GPIOS_FLAGS		0
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_RESET_GPIOS_PIN			12

To fix this, I used this hacky code which updates the prop_values based on the content of the gpio-map:

diff --git a/scripts/dts/extract/globals.py b/scripts/dts/extract/globals.py
index 8f1097a803..a835e2fa89 100644
--- a/scripts/dts/extract/globals.py
+++ b/scripts/dts/extract/globals.py
@@ -331,7 +331,7 @@ def build_cell_array(prop_array):
 
     return ret_array
 
-def gpio_map_lookup(cell_parent, gpio_index):
+def gpio_map_lookup(cell_parent, gpio_index, prop_values):
     index = 0
     map_array = []
 
@@ -366,6 +366,15 @@ def gpio_map_lookup(cell_parent, gpio_index):
         map_array.append(raw_map[index:index+array_cell_size])
         index += array_cell_size
 
+    # if prop_values, then update the # of parent_specifier_size
+    if prop_values != None:
+        index = 0
+        while index < parent_specifier_size:
+            # assign prop_value skipping controller phandle
+            prop_values[index + 1] = map_array[gpio_index][child_specifier_size + 1 + index]
+            index += 1
+        print("AFTER ", prop_values)
+
     # Return the gpio controller phandle matching the provided index
     return phandles[map_array[gpio_index][child_specifier_size]]
 
@@ -393,7 +403,7 @@ def extract_controller(node_path, prop, prop_values, index,
             # parent is a 'gpio nexus node' (ie has gpio-map)
             try:
                 # controller is to be found in the map, using elem[1] as index
-                cell_parent = gpio_map_lookup(cell_parent, elem[1])
+                cell_parent = gpio_map_lookup(cell_parent, elem[1], prop_values)
             except IndexError:
                 raise Exception("GPIO index not available in gpio-map")
 
@@ -459,7 +469,7 @@ def extract_cells(node_path, prop, prop_values, names, index,
             # parent is a 'gpio nexus node' (ie has gpio-map)
             try:
                 # controller is to be found in the map, using elem[1] as index
-                cell_parent = gpio_map_lookup(cell_parent, elem[1])
+                cell_parent = gpio_map_lookup(cell_parent, elem[1], None)
             except IndexError:
                  raise Exception("GPIO index not available in gpio-map")

And ended up with:

#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_POWER_GPIOS_CONTROLLER		"GPIO_0"
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_POWER_GPIOS_FLAGS		0
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_POWER_GPIOS_PIN			2
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_RESET_GPIOS_CONTROLLER		"GPIO_2"
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_RESET_GPIOS_FLAGS		0
#define DT_NXP_KINETIS_UART_4006D000_UBLOX_SARA_R4_4006D000_SARA_R4_MDM_RESET_GPIOS_PIN			2

@erwango
Copy link
Member Author

erwango commented May 7, 2019

@Hashcode, Txs for the info, it worked initially, but it seems I've not tested the refactoring enough. Let me rework that.

@erwango
Copy link
Member Author

erwango commented May 7, 2019

@ulfalizer, here is the last batch, which has the merit of fixing bug reported by @Hashcode (so slightly more complex treatment) and I hope fixing your comments (hence somewhat more readable).

@erwango erwango requested a review from ulfalizer May 7, 2019 09:58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call it _ instead of unused. That's common in Python, and pylint knows not to flag it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, thanks for the hint.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is "v0.3" a typo? Can't find that version online.

Copy link
Member Author

@erwango erwango May 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's available here: https://github.com/devicetree-org/devicetree-specification/blob/4b1dac80eaca45b4babf5299452a951008a5d864/source/devicetree-basics.rst#nexus-nodes-and-specifier-mapping.
"Soon to be released" according to maintainer.

EDIT: I omitted to mention that this is already supported by zephyr dtc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure it'll be called v0.3?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current one is v0.2, so I guess this is a reasonable assumption (https://www.devicetree.org/)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad idea to refer to a v0.3 version that's not out and not sure to be called v0.3 I think. Could say something like "in the upcoming (presumably v0.3) Device Tree specification" instead.

Small typo: devide -> device

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More of a comment, but instead of "aim of this function...", it might be better to say what the function does.

"This function takes a foo and a bar and returns a (baz, qaz) tuple. If foo can't be found, this other value is returned instead", etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this part. How is child_specifier_size ("The number of 32-bit cells required to specify this component", according to the DT spec) related to phandles?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gpio-map is encoded in the following way:

        gpio-map = <0 0 &soc_gpio1 1 0>,                   
                   <1 0 &soc_gpio2 4 0>,
                   <2 0 &soc_gpio1 3 0>,
                   <3 0 &soc_gpio2 2 0>;

Taking the first line:
0 0: Child specifier (pin number, pin flag)
&soc_gpio2: GPIO controller phandle
1 0: Parent specifier (pin number, pin flag)

At this point we're looking for GPIO controller phandle which is the element number 'child_specifier_size+1' in the line.

About gpio-map pin flags (does not relates directly to your question, but this might be required for the full comprehension of the change):
Assuming optional params gpio-map-mask and gpio-map-pass-thru are omitted, child and parent specifier pin flags are not taken into account and pin flag used is the one provided in calling node (typically used in shield overlay file), which is the behavior we expect, at least in current shield use case. This is "Assumption 2".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICS, this is looking at #gpio-cells though. It's saying "the number of GPIO cells + 1 is a phandle". Seems weird to me.

Sorry if I'm missing something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So:
0 0: Child specifier (pin number, pin flag) -> length provided by current node's #gpio-cell
&soc_gpio2: GPIO controller phandle
1 0: Parent specifier (pin number, pin flag) -> length provided by GPIO controller's #gpio-cell

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're never indexing into gpio-map though. You're taking #gpio-cells + 1 and directly treating that as a phandle.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, Txs!

@erwango erwango requested a review from ulfalizer May 7, 2019 12:03
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Now that the length of each entry in 'gpio-map' is known..." maybe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this could be called gpio_map_entries or the like?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this could be called gpio_map?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...then this would read as

gpio_map_entries.append(gpio_map[index:index+array_cell_size])

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this looking up the right element?

Note that it's not comparing gpio_index against item[0] for each item in map_array, unlike the code above it.

Could maybe do something like this:

for entry in gpio_map_entries:
    if entry[0] == gpio_index:
        parent_controller_phandle = entry[child_specifier_size]
        ...
        return phandles[...]

# gpio_index does not appear in gpio-map
return None, None

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I kinda assumed first cell of each raw would be same as raw index.
This is indeed a shortcut, as it could be designed otherwise.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could get rid of gpio_map_entries at this point, and do this:

for i in range(0, len(gpio_map), array_cell_size):
    entry = gpio_map[i:i+array_cell_size]
    if entry[0] == gpio_index:
        ...
        return ...

# gpio_index did not match any entry in gpio-map
return None, None

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and reworked comments

@erwango erwango requested a review from ulfalizer May 7, 2019 13:42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*optional

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, txs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to update this comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still says "raws". Could say "the size of each entry in 'gpio-map'" or the like.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh... maybe 'raws' is a typo for 'rows'. I kept reading it as something "raw".

"Before parsing, we need to know the row size in 'gpio-map'", maybe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, fixed

gpio-map is a property of "nexus node", defined in dts v0.3.
It allows to describe a pin connector so it can be referenced
through phandles and hence used in expansion device nodes like a
shield header (typically implemented through overlays).

This change implements gpio controller resolution through these maps.
Few assumptions were taken in order to simplify the implementation.
These assumptions bring some limitations to the use of gpio-map
but my understanding is that this should still allow to cover most
use cases.

Assumptions:
-gpio-size is the same for all gpio-controllers referenced in a map
-optional properties gpio-map-mask and gpio-map-pass-thru are
supposed to be omitted
The understanding of this last assumption is that flags provided in
the expansion device node will overwrite the connector flags.

In a latter stage, when need happen, these limitations can be
revisited to unlock fully fledged gpio-map usage.

Fixes zephyrproject-rtos#15637

Signed-off-by: Erwan Gouriou <[email protected]>
@erwango erwango requested a review from ulfalizer May 7, 2019 14:08
gpio_map = reduced[cell_parent]['props']['gpio-map']

# Before parsing, we need to know 'gpio-map' row size
# gpio-map raws are encoded as follows:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*rows

Copy link
Contributor

@ulfalizer ulfalizer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code nits fixed (except one raws -> rows typo).

Not an expert on how this is actually used, so someone else also ought to check.

Thanks for putting up with the nitting.


return ret_array

def child_to_parent_unmap(cell_parent, gpio_index):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Unmap"?

Copy link
Member Author

@erwango erwango May 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt child_to_parent was not enough specific.
map_extract?

Copy link
Contributor

@ulfalizer ulfalizer May 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gpio_map_index_to_controller or something maybe (wonder if _index_ could be _id_ too).

Maybe cell_parent could just be called node_path, since it's not important to the function itself that it's a parent of something that you're passing in.

Just random ideas though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gpio_map_child_to_parent ?

@erwango
Copy link
Member Author

erwango commented May 7, 2019

Thanks for putting up with the nitting.

Thanks for the in deep review

@erwango
Copy link
Member Author

erwango commented May 7, 2019

@mike-scott
Copy link
Contributor

@mike-scott, updated https://github.com/erwango/zephyr/tree/test_14057_gpio_map with latest changes

Thanks! I'll try again in a bit.

@mike-scott
Copy link
Contributor

@erwango nice job, newest change fixes the pin assignment.

@mike-scott
Copy link
Contributor

@MaureenHelm Can you take a look as I believe MCR20A and possibly other NXP boards have the potential to be used as shields including GPIO pin header assignments.

@MaureenHelm
Copy link
Member

@MaureenHelm Can you take a look as I believe MCR20A and possibly other NXP boards have the potential to be used as shields including GPIO pin header assignments.

Yes, MCR20A needs this feature to be converted to a shield (#7462). There is also an NXP sensor shield (#10198). I haven't studied this PR in detail yet, but at first glance it looks great.

Copy link
Contributor

@mike-scott mike-scott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nashif nashif merged commit 1e314df into zephyrproject-rtos:master May 8, 2019
@erwango erwango deleted the dev_gpio_map branch September 3, 2019 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Devicetree area: Shields Shields (add-on boards)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support of device tree gpio-map

5 participants