-
Notifications
You must be signed in to change notification settings - Fork 7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] scripts: extract_dts_includes.py: enhance #6761
Conversation
Codecov Report
@@ Coverage Diff @@
## master #6761 +/- ##
=======================================
Coverage 52.36% 52.36%
=======================================
Files 195 195
Lines 24696 24696
Branches 5128 5128
=======================================
Hits 12931 12931
Misses 9695 9695
Partials 2070 2070 Continue to review full report at Codecov.
|
f66bae9
to
9b3c148
Compare
80ed611
to
a6089c5
Compare
af8b56a
to
bd49e17
Compare
recheck |
dcb4a6f
to
ae6017a
Compare
9694980
to
b79938f
Compare
35de025
to
e96bb35
Compare
e96bb35
to
2db8a16
Compare
Add a common binding for pinctrl devices to be included by SoC specific bindings. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Add a common binding for GPIO devices with pinctrl backend. To be included by SoC specific bindings. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Add generic bindings for clock consumers and clock providers. Add a common binding for fixed clocks. To be included by SoC specific bindings. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Extend pinctrl client device bindings to allow pinctrl to replace the pin initialisation currently done by the SoCs/boards pinmux.c: - UART - SPI - I2C - CAN Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Variables 'names' is copying value from 'reduced' dict and gives illusion that any computation could be done on copied data. Problem is that later computation on 'names' will modify data in 'reduced'. Use deepcopy in order to avoid erasing thing in reduced. Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
Use EDTS database to create and access DTS info. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Extract compatible info and make it available by defines. This way the compatible info of all activated devices can be used in drivers. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Support more clocks related directives (besides clocks): - clock-names - clock-output-names - clock-indices - clock-ranges - clock-frequency - clock-accuracy - oscillator - assigned-clocks - assigned-clock-parents - assigned-clock-rates Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
For pin-controller and clients the following additional information is generated: Pin controller nodes -------------------- For a pin controller node five data sets are extracted from the device tree and provided in generated_dts_board.h. - FUNCTION For all active client nodes that reference a pin-controller by pinctrl-x(&pinctrl, ...) FUNCTION defines are generated. The function equals the client node. - STATE_NAME For all pinctrl names of pinctrl-x directives of active client nodes STATE_NAME defines are generated. This is mostly to allow deduplication of commonly used state names such as e.g. “default”. - PINCTRL_STATE For all pinctrl-x directives of active client nodes PINCTRL_STATE defines are generated. The pinctrl state references the FUNCTION (aka. node) it is given in. The pinctrl state also references the STATE_NAME given in the pinctrl-names directive associated to the pinctrl-x directive. All the pins that a pinctrl state controls are regarded to be a pin group. The name of the pin group is the same as the name of the pinctrl state. - PINCTRL For all subnodes of pin configurations referenced by active client nodes - pinctrl-x(&xxx, pinconf_a, ...) - PINCTRL defines are generated. The pinctrl references the FUNCTION (aka. node) it is referenced from. The pinctrl also references the PINCTRL_STATE it is referenced from. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
GPIO ranges info is added to pin controller nodes nad GPIO nodes: Pin controller nodes -------------------- - GPIO_RANGE For all gpio-ranges directives of active GPIO nodes GPIO_RANGE defines are generated. GPIO nodes ---------- - GPIO_RANGE For all gpio-ranges directives of active GPIO nodes GPIO_RANGE defines are generated. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Extract info of all devices activated. Add this info to the top level node to allow drivers to use this info. Info of devices activated is either taken from the <device>-controller directive (e.g. gpio-controller, pin-controller) or detected by heuristics if the <device>-controller directive is not foreseen for a device in the DT specification or Linux. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
'defs' variable is used and passed as a parameter in the vast majority of the functions of extract_dts_includes script. Set this variable global Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org> Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
For testing the default dts bindings can now be replaced by test versions. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Test correct generation of defines for the pinctrl directive in device trees. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While there are definitely some good things, I think that PR should not be merged as is as it introduced too much new concepts and that needs to be discussed one by one.
Blocking for now.
Here are my main concerns regarding this PR (among good things): About the way of working: 2- It is difficult to apprehend/review/comment each one of these concepts without an example of its use in actual code. Besides, w/o illustration, interest of the feature is unclear to the reader. Each new addendum should come with an example of usage in a driver (in a dedicated PR), so the usage and the usefulness is demonstrated. EDIT: Just to be clear: my point is not to block the introduction of new features, but really to fasten the discussions by enabling the review process which could not take place today. Then, some parts maybe accepted as is, some rejected and some accepted after modification. But today, there is no review. About the content: 4- One commit introduce dev- directive to establish top level nodes as controllers even when not existing in DT specification. This is conflicting with bus-master concept already present in Zephyr code base and might create confusion with extisting dts -controllers. As is, the need for this addition is unclear, would require and example (cf point 2) |
Thank you for the review. This PR will change as most of the defines can be replaced by EDTS. This is a work in progress. I will move from defines to EDTS. What really would help is if we can come up with:
The full picture is in #5799 as always. This is a cut out specifically for review.
The full picture is in #5799 as always. But I will see how to even split that in more PRs after the change to EDTS.
I agree (see above). The only unclear thing is what should remain a define also? Is there a concept?
I think the defines for device controllers can be removed alltogether. They were necessary before EDTS. The info can now be queried from the EDTS when needed. |
Can you switch from insert_structs to edts.insert_device_property ?
I would closely follow the Device Tree layout e.g. "clocks/controller", "clocks/0/bus", .... insert_device_property allows to specify the property_path when inserting info into EDTS.
I´m quite unshure here. At least the legacy defines that are currently generated have to be generated. About new ones I don´t have a clear view. |
# @param device_id | ||
# @param property_path Path of the property to access | ||
# (e.g. 'reg/0', 'interrupts/prio', 'label', ...) | ||
# @param property_value value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way it works today is that we enter a top level property and a dict associated.
For instance:
'deflabel: interrupts'
("new_structs: [{'data': [33, 0], 'labels': ['irq', 'priority']}, {'data': "
"[34, 0], 'labels': ['irq', 'priority']}]")
''
Would be easier to stick to that in a first iteration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would become:
device_id = edts.device_id(compatible, ....) # or other helper function - TBD
edts.device_insert_property(device_id, 'interrupts', [{'data': [33, 0], 'labels': ['irq', 'priority']}, {'data': "
"[34, 0], 'labels': ['irq', 'priority']}])
## | ||
# @brief Insert property value for the device of the given device id. | ||
# | ||
# @param device_id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using device_id will impose to generate device id each time before calling insert_device_property.
It would be easier to set node_address + compat* in the arguments and then compute device_id inside the function
*: compatible could be computed from node_address, but requires to know 'reduced'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using device_id will impose to generate device id each time before calling insert_device_property.
- On filling the EDTS database the device_id should be be generated at the beginning of extract_ and then re-used. reduced for 'compatible' is available here anyway.
def extract_<whatever>(node_address, ...)
node = ....
device_id = edts.device_id(node[props][...], ...)
There may also be a helper function in extract_dts_includes:
def extract_device_id(node_address):
# extract necessary values from reduced
return etds.device_id(compatible, base_address, offset)
- On using the ETDS database the device id will be queried. Reduced is not necessary (and not available).
for device_id in edts.compatible_devices_id(compatible):
# do something, eg
label = edts.device_property(device_id, 'label')
It would be easier to set node_address + compat* in the arguments and then compute device_id inside the function
This can not be part of EDTSDatabase as this requires reduced to be available which breaks data encapsulation. There can well be a function in extract_dts_includes that provides this, e.g.
def extract_edts_device_property(node_address, property_path, property_value):
# extract necessary values from reduced
device_id = etds.device_id(compatible, base_address, offset)
etds.insert_device_property(device_id, property_path, property_value)
# @return property value | ||
# | ||
def device_property(self, device_id, property_path, default="<unset>"): | ||
property_value = self._edts['devices'][device_id] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be updated vs the latest version.
(And will likely require a more efficient (and iterative) parsing function)
s = s.upper() | ||
return s | ||
|
||
def device_id(self, compatible, base_address, offset): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is 'offset'?
I think the function should take node_address and compatible into account.
node_address should look like: /soc/i2c@40005800/hts221@5f
From this is should be possible to build device_id: <compatible>_40005800_5F
And while I don't have any example yet, I think there could be more address level than that, so it should be taken into account upfront: <compatible>_<addr_1>_<addr_2>_<...>_<addr_n>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took offset only as an assumption from the string you provided as @galak ´s request. You may also call it index, ... Maybe @galak can explain what he would like device id to be build from and look like.
I don´t think it is important how device id will be generated as long as it is unique. My first proposal was to just use the 'label' property as this is unique for all activated devices.
In my view device_id is just a unique reference to a device struct. It should not be used for other purposes (like generating define labels from it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll let @galak provide more information here
# device-type: any of ['GPIO', 'SPI', 'CAN', ...] - 'id' from <binding>.yaml | ||
# label: any of ['UART_0', 'SPI_11', ...] - label directive from DTS | ||
# | ||
class EDTSDatabase(Mapping): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For clarity, it would be nice to split between producer and consumer functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For clarity, it would be nice to split between producer and consumer functions.
I tried to by the function names:
- Producer
- insert_device_property
- save
- Consumer
- device_property
- compatible_devices
- compatible_devices_id
- load
I´m open to better method names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So a clear split in the file would be good. get_... for consumer could be nice as well
What about sub classes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about sub classes?
OK will go for mixin classes like codegen uses to separate the different functions.
@b0661 , thanks for the feedback. I made some comments to edts class.
Added some comments. In a first step it would be easier to stick with existing APIs (or at least something close).
Once EDTSDatabase are in use, we can update internal database structure.
My rough view is that we should target to keep #define's generated from 'aliases' and CONFIG_xxx. |
Replace
by
with helper function:
I think this is pretty close.
There should still be a convention how to pack DTS info into EDTS. You already created one with the conversion to dict entries and lists. |
Overview
To ease the maintenance and ongoing development extract_dts_includes.py is refactored.
To manage devices efficiently extract_dts_includes.py is extended/ amended:
To support pinctrl devices extract_dts_includes.py is extended:
The PR is a cut-out from PR #5799 for review but can be independently applied.
Motivation for or Use Case
The prime motivation is to be able to create pin controller drivers that can configure the pins on startup by the information from the device tree in a standardized way. Therefor all relevant device tree information must be available in generated_dts_boards.[h,conf] in a way that can easily be used to generate structured data at build time.
Generation of structured data is done by CodeGen that reads generated_dts_boards.conf
Design Details
To allow modularization of the monolitic script all global data and functions are factorized to a python module that can be imported by other modules.
The extraction of device tree directives is added as separate python modules that are derived from the common base class DTDirective:
Test Strategy
This PR includes a unit test that tests the correct generation of defines for the pinctrl directive in device trees. It also tests that the default behaviour for the pinctrl directive stays the same.
A working proof of concept for STM32F0x drivers using the extracted device tree information is available in PR #5799.
Signed-off-by: Bobby Noelte b0661n0e17e@gmail.com