Browse Source

drivers: intc: irqstr: add PM support

Add support for PM. The strategy is as follows:

	1) For level 1 interrupts: don't care, these don't
	require the PM domain of irqsteer to be turned on
	since they are, well, direct.

	2) For level 2 interrupts: use the reference count
	of the dispatchers.

Upon doing a get() on a dispatcher with its reference count
set to 0, before enabling the IRQ (meaning accessing the
reg. space) increment the reference count of the irqstr device
(which will result in the PM domain being enabled if 0).

Upon doin a put() on a dispatcher with its reference count
set to 1, after disabling the IRQ (meaning accessing the
reg. space) decrement the reference count of the irqstr device
(which will result in the PM domain being disabled if 0).

In summary, the PM domain of the device will be enabled if
at least one dispatcher is in use. On the other hand, the
PM domain of the device will be disabled if there's no
dispatchers in use (assuming there's no other dependencies).

Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
pull/76975/head
Laurentiu Mihalcea 9 months ago committed by Carles Cufí
parent
commit
202794273d
  1. 30
      drivers/interrupt_controller/intc_nxp_irqsteer.c

30
drivers/interrupt_controller/intc_nxp_irqsteer.c

@ -229,6 +229,8 @@ @@ -229,6 +229,8 @@
#include <zephyr/cache.h>
#include <zephyr/sw_isr_table.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/pm/device.h>
#include "sw_isr_common.h"
@ -346,12 +348,20 @@ static void _irqstr_disp_enable_disable(struct irqsteer_dispatcher *disp, @@ -346,12 +348,20 @@ static void _irqstr_disp_enable_disable(struct irqsteer_dispatcher *disp,
static void _irqstr_disp_get_unlocked(struct irqsteer_dispatcher *disp)
{
int ret;
if (disp->refcnt == UINT8_MAX) {
LOG_WRN("disp for irq %d reference count reached limit", disp->irq);
return;
}
if (!disp->refcnt) {
ret = pm_device_runtime_get(disp->dev);
if (ret < 0) {
LOG_ERR("failed to enable PM resources: %d", ret);
return;
}
_irqstr_disp_enable_disable(disp, true);
}
@ -363,6 +373,8 @@ static void _irqstr_disp_get_unlocked(struct irqsteer_dispatcher *disp) @@ -363,6 +373,8 @@ static void _irqstr_disp_get_unlocked(struct irqsteer_dispatcher *disp)
static void _irqstr_disp_put_unlocked(struct irqsteer_dispatcher *disp)
{
int ret;
if (!disp->refcnt) {
LOG_WRN("disp for irq %d already put", disp->irq);
return;
@ -372,6 +384,12 @@ static void _irqstr_disp_put_unlocked(struct irqsteer_dispatcher *disp) @@ -372,6 +384,12 @@ static void _irqstr_disp_put_unlocked(struct irqsteer_dispatcher *disp)
if (!disp->refcnt) {
_irqstr_disp_enable_disable(disp, false);
ret = pm_device_runtime_put(disp->dev);
if (ret < 0) {
LOG_ERR("failed to disable PM resources: %d", ret);
return;
}
}
LOG_DBG("put on disp for irq %d results in refcnt: %d",
@ -556,11 +574,18 @@ static void irqsteer_isr_dispatcher(const void *data) @@ -556,11 +574,18 @@ static void irqsteer_isr_dispatcher(const void *data)
}
}
__maybe_unused static int irqstr_pm_action(const struct device *dev,
enum pm_device_action action)
{
/* nothing to be done here */
return 0;
}
static int irqsteer_init(const struct device *dev)
{
IRQSTEER_REGISTER_DISPATCHERS(DT_NODELABEL(irqsteer));
return 0;
return pm_device_runtime_enable(dev);
}
@ -572,9 +597,10 @@ static struct irqsteer_config irqsteer_config = { @@ -572,9 +597,10 @@ static struct irqsteer_config irqsteer_config = {
};
/* assumption: only 1 IRQ_STEER instance */
PM_DEVICE_DT_INST_DEFINE(0, irqstr_pm_action);
DEVICE_DT_INST_DEFINE(0,
&irqsteer_init,
NULL,
PM_DEVICE_DT_INST_GET(0),
NULL, &irqsteer_config,
PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY,
NULL);

Loading…
Cancel
Save