-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Enable wakeup with uart shell from PM2 on RW612, fix uart issues #89760
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
Enable wakeup with uart shell from PM2 on RW612, fix uart issues #89760
Conversation
@bjarki-andreasen this PR kind of hinges on the new API I added to the power_device_lock interface, which is in the 2nd commit, can I get your feedback about that one before I open this up to wider review and start dealing with compliance/twisters/etc. And the first commit is a refactor in that subsystem file as well so you might also be interested there. The 4th commit is showing the use case I needed something like this for |
TL:DR, API makes sense and is needed here, we need a bit more to make it truly transparent to the user I think :) You have definitely discovered an issue I have not considered at all, dealing with devices that are "suspended", but are still "active" enough to wake the system :) A driver registering to pm state change events is ok, and a driver being able to check it a state would disable it is also ok, so I think the API is reasonable, and needed for this usecase :) From a users perspective, how would this work? I'm just wondering, what if PM3 is desired? the UART being a wakeup source should prevent PM3 in this case right? so it would need to have a new set of |
TL:DR, I give you a rambling response about various things.
Yes, I think this API could be generally useful to users of Zephyr as well and is not just niche for this one type of case in this PR. An alternative I considered is to provide an API which gives some kind of list of states which would disable a device, as this might have less runtime performance overhead than doing these looping checks on every notification. But for this both the implementation and interface seemed like it would be a lot more awkward and obviously then involves user needing to storing more data in memory for each device and recall it later. I didn't want to go that route but I present the idea to you now in case you disagree with the option I chose.
Yes, it's a bit strange for me to understand as well from the documentation, about what it means how it says that the peripheral will be in "retention state" yet acts like it is active enough still to wake up. And a further complication for this particular peripheral, which is not addressed on this PR, is that it apparently can be used to wake up even from deeper sleep modes, although I'm not sure if this is possible on this platform despite the information being in the reference manual as this could be a copy paste error. But for this uart IP generally, I guess it has the ability to wakeup the system partially in order to trigger some events on some kind of mux fabric (cc @carlescufi btw) without causing a wakeup interrupt to the core. The idea I guess therefore being that it can support a situation where the uart receives some data and triggers a DMA to handle receiving it to memory all without waking up the processor core or executing any software at all. I'm not sure how to even begin approaching that type of use case on Zephyr but it's not something that I think is important right now to us (nxp maintainers).
If wakeup sources are determined solely by the DT right now, then I don't personally think that this is how the wakeup-source property should be interpreted. That is to say,
For this situation on RW, it actually is partially a case as I said above of unclear documentation. The RM says that all the peripherals are put into "retention state" and from programmer perspective it is certainly true that for the most part they stop working. I may need to track down who is the chip architects to confirm want "retention" means, but what I have found, at least with the uart, is that maybe what actually happens is just that the clock to the peripherals is lost due to most of the clock generators on the system being gated in PM2. The motivation on this PR for example to change the main clock source during PM2 is because that sets up the clock tree in the one possible configuration for a clock to reach the flexcomm. So maybe it is actually inaccurate to say that the peripheral UART (or even the whole peripheral domain) is actually disabled in PM2, it's just practically going to be the case. Now with a PR like this it starts to muddy which part of the system (power driver, user DT, clock control driver, device driver) is responsible for knowing how the clock tree works and what is the state of it in various power modes. (cc @danieldegrasse). On the other hand, the UART in PM2 is not able to communicate to it's partner due to the changed clock source changing the baud rate, so maybe it is accurate to call it disabled.
First of all, I'm assuming by resume and suspend, you meant get and put. I think, it's not a perfectly clean solution on this PR, and maybe will need changed someday, but what I think is my answer for this right now is basically like the following: pm_device_runtime_get called on the uart device will prevent the system from entering PM2, as you said. This is because the UART cannot function normally for the application/board setup in PM2 due to UART communication relying on the agreed upon baud rate, which, as seen in this PR, will change as as result of entering PM2 due to the faster clock source not being available. So if user intends to transmit or have a lot of incoming communication (to the point that the repeated wakeups and sleeps would overload the system, and they know that), then they will want to just lock out PM2, or generally, any state which would not allow the UART to communicate to it's partner normally. pm_device_runtime_put called on the UART device could allow system to enter PM2. This would be when from user/system perspective we don't expect or know of any UART activity to happen. Such as in the case of the shell where we interact on human timescale and therefore next uart activity is unknown and eons away in cpu time, but we still expect it someday, then user sets wakeup source DT property. If UART in DT has the wakeup-source property, then as seen in this PR, it will call the (eventually platform specific, unless a new abstraction is proposed) wakeup_cfg function, and the (platform agnostic) clock_control_configure function. For situations like PM3 enabled where the UART wakeup alone is not sufficient to wakeup, user is responsible to know the platform and either 1) not enable PM3, 2) have some other mechanism to know when someone would be able to be using the shell and lock out PM3 from that information, or 3) design the board to wake up from UART activity with the deep sleep wakeup pins. This is maybe not the best and maybe you are right that it might be cleaner ultimately to describe some other information in DT but for now from nxp perspective I am ok with the situation of things that I have on this PR described above. |
0abbec4
to
edc7974
Compare
One of the core design principles I'm adhering to regarding device PM is to keep it as open and flexible as possible, any device can be a power domain, any device can get/put any other device, and indeed, any device should be able to lock and react to any pm state change. I don't think there is a one solution fits all when it comes to the specifics of an SoC, I'm just clinging on to the simple "bottom/up user requests device when needed, drivers and soc do whatever to meet this" philosophy of the PM enhancement RFC :) So far seems promising |
data->pm_policy_state_lock = false; | ||
pm_policy_device_power_lock_put(dev); | ||
} else { | ||
/* can't block systemn workqueue so keep re-submitting until it's done */ |
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.
NIT, typo extra 'n'
drivers/serial/uart_mcux_flexcomm.c
Outdated
base->BRG = data->old_brg; | ||
} | ||
} | ||
#endif /* CONFIG_PM_POLICY_DEVICE_CONSTRAINTS */ |
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.
Update comment.
static uint32_t frgclksels[4]; | ||
static uint32_t frgctls[4]; | ||
|
||
if (clock_name & 0x80) { |
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 the special bit at 0x80?
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's just decoding the arbitrary value given in the DT clock header that is specific for this driver. I could give the bit a macro name in the header
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.
If the device header doesn't have a mask for it, then just put a comment block above it as to what it is for future me/you.
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 think I will just make a descriptive macro mask on the next push in the dt binding header
@@ -10,6 +10,7 @@ config UART_MCUX_FLEXCOMM | |||
select SERIAL_SUPPORT_INTERRUPT | |||
select SERIAL_SUPPORT_ASYNC if \ | |||
DT_HAS_NXP_LPC_DMA_ENABLED | |||
select PM_POLICY_DEVICE_CONSTRAINTS if PM |
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 title references RW612 where this gets set already if PM is enabled (
zephyr/soc/nxp/rw/Kconfig.defconfig
Line 74 in fbdf4b9
config PM_POLICY_DEVICE_CONSTRAINTS |
But I'm guessing that since this is shared IP we need this here. We might need to think through a bit this config and why we set it in the RW defconfig... yet still need to set it in the drivers Kconfig
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.
Yes, I put this here because it is not specific to RW, even though RW is the only platform right now in tree that is enabling PM deep enough to disable the UART. But any platform that disables the UART on low power mode will need this dependency to avoid the garbage character.
data->old_brg = base->BRG; | ||
data->old_osr = base->OSR; | ||
base->OSR = 8; | ||
base->BRG = 0; |
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.
How did you decide on these values. A comment would be helpful.
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.
There already is a comment on line 1168-1171 explaining that we are switching to the lowest baud rate.
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.
True, but how did you calculate 8 and 0?
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.
There is no calculation involved, BRG is the baud rate generator register and I put 0 which is the min, and OSR is the clocks per bit register which I put 8 which is the max
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 would help if some of this is added to the comment. Not a blocker.
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.
update copyright year
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.
update copyright year
drivers/serial/uart_mcux_flexcomm.c
Outdated
|
||
if (data->pm_policy_state_lock) { | ||
/* we can't block on TXidle mask in IRQ context so offload */ | ||
k_work_submit(&data->pm_lock_work); | ||
} | ||
} | ||
#endif |
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.
#endif | |
#endif /* CONFIG_PM_POLICY_DEVICE_CONSTRAINTS */ |
drivers/serial/uart_mcux_flexcomm.c
Outdated
@@ -26,6 +27,8 @@ | |||
#include <fsl_inputmux.h> | |||
#endif | |||
|
|||
#define UART_IS_WAKEUP (IS_ENABLED(CONFIG_PM) && DT_ANY_INST_HAS_BOOL_STATUS_OKAY(wakeup_source)) |
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.
*Nit not specific to UART, is specific to mcux_uart_flexcomm,
#define UART_IS_WAKEUP (IS_ENABLED(CONFIG_PM) && DT_ANY_INST_HAS_BOOL_STATUS_OKAY(wakeup_source)) | |
#define MCUX_UART_IS_WAKEUP (IS_ENABLED(CONFIG_PM) && DT_ANY_INST_HAS_BOOL_STATUS_OKAY(wakeup_source)) |
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 put flexcomm but don't like mcux namespace being used in zephyr, since it's not an mcux product, it's just confusing
drivers/serial/uart_mcux_flexcomm.c
Outdated
k_work_init(&data->pm_lock_work, config->pm_unlock_work_fn); | ||
#endif | ||
|
||
#if UART_IS_WAKEUP | ||
config->wakeup_cfg(); | ||
pm_notifier_register((struct pm_notifier *)&data->pm_handles); |
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.
You probably don't need the cast.
There is currently a bug where when entering low power modes, there is a garbage character sent if the UART is in the middle of a transmit when entering low power mode. This is because the fifo interrupt happens when last character is pulled by transmitter from fifo and then we unlock PM constraints at that moment, instead of waiting for actual transmitter to become idle. Fix by adding work item to check for this when needed. Signed-off-by: Declan Snyder <[email protected]>
Refactor this code so it has less nesting and is able to share some code between functions, by making a function to find the device constraints object which can be called before doing operations using it. Signed-off-by: Declan Snyder <[email protected]>
Add an API function that can be used by client code to check if a state disables a device. Signed-off-by: Declan Snyder <[email protected]>
On RW, normal configuration has all clock generators gated in PM2. Only the LPOSC is available for main clock source since it is a low power clock. Many of the peripherals on the chip are still "on" and do need a main clock source in order to be effective as wakeup sources to the chip as intended. So we should make this switch for PM2 specifically in order to achieve desired wakeup capabilities. Signed-off-by: Declan Snyder <[email protected]>
Add the feature for the flexcomm uart to be able to be a wakeup source from low power modes. To be able to do this on a relevant platform, the DT node for the UART needs to have the wakeup-source property and define a "sleep" clock. The details of handling the sleep clock and default clock are still platform specific but handled by the clock control driver of the platform, so that this code should be able to be applicable to any platform that follows the same DT definition. Signed-off-by: Declan Snyder <[email protected]>
Following the new feature in the flexcomm driver to be able to wake up from low power mode, the clock control drivers have to handle the platform specific details, so this commit adds to the already ugly mess that is the LPC syscon driver which is used by RW currently and makes the required devicetree changes. Make the console/shell uart on the FRDM_RW612 take advantage of this by default. Signed-off-by: Declan Snyder <[email protected]>
|
@mmahadevan108 @DerekSnell if you are good with the responses please give +1 |
Support UART wakeup from PM2 with shell on RW612.
Changes: