-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
drivers: video: Introduce macro to deal with endpoints #73023
Conversation
This needs testing after #72950 is merged. |
7bc3a35
to
3fb4e4f
Compare
Looks promising, would it make sense to have in/out type encoded/described? |
3fb4e4f
to
e23a258
Compare
I picked the first nibble to encode a custom field that will say either "IN" or "OUT" or "EITHER" or "NONE", which is showcased here: |
bcddde7
to
5f1e281
Compare
This is now rebased on top of #73009. |
@josuah : I will need sometimes to look at this closer. But does this resolve the "circular dependency" and the "chicken-egg" init order issues or this is just APIs to deal with endpoints ? So, my questions
|
With these, can we obtain a reference to the video object pointed by the remote-endpoint so that we don't need to use direct phandle references in DT (currently this method is used extensively in Zephyr) ? Yes, the various The driver would still have to do something like this to follow the remote endpoint, and then call video_dt_spec on that:
Maybe a If so, how do you handle the case that the "remote" video object is not available yet (due to the init order priority) ? As an example, the CSI driver needs to initialize before the mt9m114 camera sensor driver to provide the master clock for the sensor. But in the CSI driver, we need to obtain a reference to the mt9m114 sensor (to propagate formats, etc.) An application connecting two video ports might also face this problem, so maybe the solution is in the samples: The calls that could be recursive (get/set feed parameters, and data movement) are set from application, after everything is initialized. Is there a chance that recursive calls (get data/controls from this device that gets data/controls from this device [...]) happens during initialization? One alternative would be to have an extra ports / endpoints / remote-endpoints are not only limit to video, they are used for display and other things too. Why don't we put these things in the zephyr core instead of the video subsystem ? This makes more sense as you said. And it looks like the "ports / port / endpoint / remote-endpoint" logic is even encoded into the devicetree tool itself: |
If some hardware datasheet defines an endpoint address 0x8 IN, and 0x80 OUT, and we encode it as 0x81 and 0x800 this could be confusing. |
5f1e281
to
d7c9533
Compare
force-push: A completely new approach, much more minimal, not specific to video, and leveraging the In the context of video devices, this would allow replacing the I think I will need to add tests for it. |
I didn't look into details yet but this is what I want to do and glad to see that you are faster :-). It should be a good work-around to retrieve the phandle of the peer device and would be very useful (as I am not sure with the current design of Zephyr DT whether it's possible to do circular dependency with remote-endpoint phandle or not). Need to pay attention that we can have either "ports -> port -> endpoint" or "port->endpoint". And of course, it should be tested working :-). |
Ah, one more point, I think this should be at the 1st time, in the video section only as |
Ah ... looking closer : It seems the macro just allow to retrieve the string specified in |
I happened to need this for UVC. :)
There is #57708 getting in the way, after which the devicetree can be converted from
I thought we could start with the most basic
I can move the macros from
Code at the origin of this PR: I might have time this week-end for this. |
Okay, will check this later. But just to emphasize that circular dependency is very important as we need "async init" mechanism as in Linux. Without this, we encounter some deadlock / chicken-egg issues (the one in mt9m114 / CSI on RT1064 and ov7770 / SmartDMA is an example which do not work on upstream up to now unless doing a work-around). I can't understand why Zephyr does not take into account all of this when designing device tree. Will create an issue (for mt9m114 / csi and ov7770 / SmartDMA) and emphasize the problem in the Circular dependency issue (I wanted to do this for a long time but always forgot). |
Ah right I forgot that phandles are also used to organize the init sequence! At the devicetree level: (step 1) the macros are generated, (step 2) the driver macros access the devicetree macros. |
I know, "async init" is more than that. But with the work-around it is sufficient to resolve the current chicken-egg issue in mt9m114 / csi and ov7770 / smartDMA as it happens at compile time due to init priority conflict. |
Add macros to access the port/endpoint constructs from drivers and application. Devicetrees currently use "port { endpoint { ... }; };" to describe interconnection between devices. With introduction of the "remote-endpoint-label = string" syntax, it is now possible to describe circular dependencies until zephyrproject-rtos#57708 is addressed. Signed-off-by: Josuah Demangeon <[email protected]>
d7c9533
to
464e59e
Compare
force-push: simplify the macro, add tests Here is a reduced version with only
To handle
|
* | ||
* @return The remote endpoint node connected to @p node. | ||
*/ | ||
#define DT_REMOTE_ENDPOINT(node) DT_NODELABEL(DT_STRING_TOKEN(node, remote_endpoint_label)) |
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.
Given real macro usages in drivers as below:
Case 1:
#define DEVICE_DT_INST_GET_SOURCE_DEV(n) \
DEVICE_DT_GET(DT_PARENT(DT_GPARENT(DT_NODELABEL(DT_STRING_TOKEN( \
DT_CHILD(DT_INST_CHILD(n, port), endpoint), remote_endpoint_label)))))
the node parameter in this case will be DT_CHILD(DT_INST_CHILD(n, port), endpoint)
Case 2:
#define DEVICE_DT_INST_GET_SENSOR_DEV(n) \
DEVICE_DT_GET(DT_GPARENT(DT_NODELABEL( \
DT_STRING_TOKEN(DT_CHILD(DT_CHILD(DT_INST_CHILD(n, ports), port_1), endpoint), \
remote_endpoint_label))))
the node parameter will be DT_CHILD(DT_CHILD(DT_INST_CHILD(n, ports), port_1), endpoint)
There's still endpoint
common for all cases. Is it possible to take endpoint in the DT_REMOTE_ENDPOINT api ?
Also, to retrieve the peer device object, we always has at least DT_GPARENT
, is it possible to also take this in the macro API ?
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.
It is possible to reduce the overhead by putting endpoint in common to each, but then comes looping over every endpoint:
#define ENDPOINT(n) DT_PROP(DT_REMOTE_ENDPOINT(n), link_parameter),
int link_parameters[] = {
DT_FOREACH_CHILD(DT_INST_CHILD(DT_DRV_INST(0), port), ENDPOINT)
};
So this means that it is also useful to expose an intermediate macro that can be used in both case, only wrapping the remote-endpoint-label -> nodelabel -> node conversion.
It will also be possible to have some macro using COND_CODE_1()
to make the "ports" vs "port" abstraction.
#define DT_PORTS(n) \
COND_CODE_1(DT_HAS_PROP(n, ports), (DT_CHILD(n, ports)), (n))
#define DT_INST_PORTS(n) \
DT_PORTS(DT_DRV_INST(n))
/* Example */
DEVICE_DT_GET(DT_GPARENT(DT_REMOTE_ENDPOINT(
DT_CHILD(DT_CHILD(DT_INST_PORTS(0), port_3, endpoint_2)))))
This will return the node that contains all the ports, for instance:
#define DT_PORTS_REMOTE_ENDPOINT(n, port, endpoint) \
DT_REMOTE_ENDPOINT(DT_CHILD(DT_CHILD(DT_PORTS(DT_DRV_INST(0)), port), endpoint))
#define DT_INST_PORTS_REMOTE_ENDPOINT(n, port, endpoint) \
DT_PORTS(DT_DRV_INST(n))
/* Example */
DEVICE_DT_GET(DT_GPARENT(DT_INST_PORTS_REMOTE_ENDPOINT(0, port_3, endpoint_1)))
Then, there is going down from the other device, and we might need the same check for "ports" present or not.
#define DT_ENDPOINT_DEVICE(n) \
COND_CODE_1(DT_PROP_HAS(DT_GPARENT(n), port), (DT_GPARENT(n)), (DT_PARENT(DT_GPARENT(n))))
/* Example */
DEVICE_DT_GET(DT_ENDPOINT_DEVICE(DT_INST_PORTS_REMOTE_ENDPOINT(0, port_3, endpoint_1)))
And then why not combine them two, as the most frequent use-case for simple drivers would be to pick the device connected through a particular endpoint:
#define DT_REMOTE_DEVICE(n, port, endpoint) \
DT_ENDPOINT_DEVICE(DT_INST_PORTS_REMOTE_ENDPOINT(0, port, endpoint))
#define DT_INST_REMOTE_DEVICE(n, port, endpoint) \
DT_REMOTE_DEVICE(DT_DRV_INST(n), port, endpoint)
/* Example */
DEVICE_DT_GET(DT_INST_REMOTE_DEVICE(0, port, endpoint))
Would it make sense to decompose the implementation this much?
The intermediate macros would need to be implemented anyway to avoid making them too large, so we might as well document and test each intermediate step.
I think the current implementation (in the commit) just helps to make a bit shortcut but still let drivers deal with "how to get the endpoint node id", "how to deal with different cases like whether there is
Another problem is that although It is much easier to make it in It's difficult to explain all by words than by code for all aspects so I made this PR, hope you don't mind, I added you as the co-author in the core commit though. Feel free to discuss. |
Great to work with IDs! This is a better API than what I proposed I think...
This is probably all what 90% of users need, and combines very well with the above: DEVICE_DT_GET_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 2, 3))
If a macro is not called, it would not cause any compilation issue. And users who want to use it can also define their
It probably cannot be put in
Good idea! Do feel free to cherry-pick the tests or snippets or skip them. |
Closing this PR to focus efforts on #80649 |
This is part of a series of proposals for incremental changes for the Video API:
This depends on:
It introduces some way to point at devicetree objects and use them in the API.
It assumes that endpoint numbers can be passed where
enum video_endpoint_id ep
is present through the API.Example:
It is then possible to refer
vid0port0out
like this: