mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 17:41:22 +00:00
net: iosm: power management
Implements state machine to handle host & device sleep. Signed-off-by: M Chetan Kumar <m.chetan.kumar@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9413491e20
commit
be8c936e54
333
drivers/net/wwan/iosm/iosm_ipc_pm.c
Normal file
333
drivers/net/wwan/iosm/iosm_ipc_pm.c
Normal file
@ -0,0 +1,333 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020-21 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include "iosm_ipc_protocol.h"
|
||||
|
||||
/* Timeout value in MS for the PM to wait for device to reach active state */
|
||||
#define IPC_PM_ACTIVE_TIMEOUT_MS (500)
|
||||
|
||||
/* Note that here "active" has the value 1, as compared to the enums
|
||||
* ipc_mem_host_pm_state or ipc_mem_dev_pm_state, where "active" is 0
|
||||
*/
|
||||
#define IPC_PM_SLEEP (0)
|
||||
#define CONSUME_STATE (0)
|
||||
#define IPC_PM_ACTIVE (1)
|
||||
|
||||
void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
|
||||
bool host_slp_check)
|
||||
{
|
||||
if (host_slp_check && ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE &&
|
||||
ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE_WAIT) {
|
||||
ipc_pm->pending_hpda_update = true;
|
||||
dev_dbg(ipc_pm->dev,
|
||||
"Pend HPDA update set. Host PM_State: %d identifier:%d",
|
||||
ipc_pm->host_pm_state, identifier);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, true)) {
|
||||
ipc_pm->pending_hpda_update = true;
|
||||
dev_dbg(ipc_pm->dev, "Pending HPDA update set. identifier:%d",
|
||||
identifier);
|
||||
return;
|
||||
}
|
||||
ipc_pm->pending_hpda_update = false;
|
||||
|
||||
/* Trigger the irq towards CP */
|
||||
ipc_cp_irq_hpda_update(ipc_pm->pcie, identifier);
|
||||
|
||||
ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, false);
|
||||
}
|
||||
|
||||
/* Wake up the device if it is in low power mode. */
|
||||
static bool ipc_pm_link_activate(struct iosm_pm *ipc_pm)
|
||||
{
|
||||
if (ipc_pm->cp_state == IPC_MEM_DEV_PM_ACTIVE)
|
||||
return true;
|
||||
|
||||
if (ipc_pm->cp_state == IPC_MEM_DEV_PM_SLEEP) {
|
||||
if (ipc_pm->ap_state == IPC_MEM_DEV_PM_SLEEP) {
|
||||
/* Wake up the device. */
|
||||
ipc_cp_irq_sleep_control(ipc_pm->pcie,
|
||||
IPC_MEM_DEV_PM_WAKEUP);
|
||||
ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE_WAIT;
|
||||
|
||||
goto not_active;
|
||||
}
|
||||
|
||||
if (ipc_pm->ap_state == IPC_MEM_DEV_PM_ACTIVE_WAIT)
|
||||
goto not_active;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
not_active:
|
||||
/* link is not ready */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm)
|
||||
{
|
||||
bool ret_val = false;
|
||||
|
||||
if (ipc_pm->ap_state != IPC_MEM_DEV_PM_ACTIVE) {
|
||||
/* Complete all memory stores before setting bit */
|
||||
smp_mb__before_atomic();
|
||||
|
||||
/* Wait for IPC_PM_ACTIVE_TIMEOUT_MS for Device sleep state
|
||||
* machine to enter ACTIVE state.
|
||||
*/
|
||||
set_bit(0, &ipc_pm->host_sleep_pend);
|
||||
|
||||
/* Complete all memory stores after setting bit */
|
||||
smp_mb__after_atomic();
|
||||
|
||||
if (!wait_for_completion_interruptible_timeout
|
||||
(&ipc_pm->host_sleep_complete,
|
||||
msecs_to_jiffies(IPC_PM_ACTIVE_TIMEOUT_MS))) {
|
||||
dev_err(ipc_pm->dev,
|
||||
"PM timeout. Expected State:%d. Actual: %d",
|
||||
IPC_MEM_DEV_PM_ACTIVE, ipc_pm->ap_state);
|
||||
goto active_timeout;
|
||||
}
|
||||
}
|
||||
|
||||
ret_val = true;
|
||||
active_timeout:
|
||||
/* Complete all memory stores before clearing bit */
|
||||
smp_mb__before_atomic();
|
||||
|
||||
/* Reset the atomic variable in any case as device sleep
|
||||
* state machine change is no longer of interest.
|
||||
*/
|
||||
clear_bit(0, &ipc_pm->host_sleep_pend);
|
||||
|
||||
/* Complete all memory stores after clearing bit */
|
||||
smp_mb__after_atomic();
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static void ipc_pm_on_link_sleep(struct iosm_pm *ipc_pm)
|
||||
{
|
||||
/* pending sleep ack and all conditions are cleared
|
||||
* -> signal SLEEP__ACK to CP
|
||||
*/
|
||||
ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP;
|
||||
ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP;
|
||||
|
||||
ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_SLEEP);
|
||||
}
|
||||
|
||||
static void ipc_pm_on_link_wake(struct iosm_pm *ipc_pm, bool ack)
|
||||
{
|
||||
ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
|
||||
|
||||
if (ack) {
|
||||
ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
|
||||
|
||||
ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_ACTIVE);
|
||||
|
||||
/* check the consume state !!! */
|
||||
if (test_bit(CONSUME_STATE, &ipc_pm->host_sleep_pend))
|
||||
complete(&ipc_pm->host_sleep_complete);
|
||||
}
|
||||
|
||||
/* Check for pending HPDA update.
|
||||
* Pending HP update could be because of sending message was
|
||||
* put on hold due to Device sleep state or due to TD update
|
||||
* which could be because of Device Sleep and Host Sleep
|
||||
* states.
|
||||
*/
|
||||
if (ipc_pm->pending_hpda_update &&
|
||||
ipc_pm->host_pm_state == IPC_MEM_HOST_PM_ACTIVE)
|
||||
ipc_pm_signal_hpda_doorbell(ipc_pm, IPC_HP_PM_TRIGGER, true);
|
||||
}
|
||||
|
||||
bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active)
|
||||
{
|
||||
union ipc_pm_cond old_cond;
|
||||
union ipc_pm_cond new_cond;
|
||||
bool link_active;
|
||||
|
||||
/* Save the current D3 state. */
|
||||
new_cond = ipc_pm->pm_cond;
|
||||
old_cond = ipc_pm->pm_cond;
|
||||
|
||||
/* Calculate the power state only in the runtime phase. */
|
||||
switch (unit) {
|
||||
case IPC_PM_UNIT_IRQ: /* CP irq */
|
||||
new_cond.irq = active;
|
||||
break;
|
||||
|
||||
case IPC_PM_UNIT_LINK: /* Device link state. */
|
||||
new_cond.link = active;
|
||||
break;
|
||||
|
||||
case IPC_PM_UNIT_HS: /* Host sleep trigger requires Link. */
|
||||
new_cond.hs = active;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Something changed ? */
|
||||
if (old_cond.raw == new_cond.raw) {
|
||||
/* Stay in the current PM state. */
|
||||
link_active = old_cond.link == IPC_PM_ACTIVE;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
ipc_pm->pm_cond = new_cond;
|
||||
|
||||
if (new_cond.link)
|
||||
ipc_pm_on_link_wake(ipc_pm, unit == IPC_PM_UNIT_LINK);
|
||||
else if (unit == IPC_PM_UNIT_LINK)
|
||||
ipc_pm_on_link_sleep(ipc_pm);
|
||||
|
||||
if (old_cond.link == IPC_PM_SLEEP && new_cond.raw) {
|
||||
link_active = ipc_pm_link_activate(ipc_pm);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
link_active = old_cond.link == IPC_PM_ACTIVE;
|
||||
|
||||
ret:
|
||||
return link_active;
|
||||
}
|
||||
|
||||
bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm)
|
||||
{
|
||||
/* suspend not allowed if host_pm_state is not IPC_MEM_HOST_PM_ACTIVE */
|
||||
if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE) {
|
||||
dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d",
|
||||
ipc_pm->host_pm_state, IPC_MEM_HOST_PM_ACTIVE);
|
||||
return false;
|
||||
}
|
||||
|
||||
ipc_pm->host_pm_state = IPC_MEM_HOST_PM_SLEEP_WAIT_D3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm)
|
||||
{
|
||||
if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_SLEEP) {
|
||||
dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d",
|
||||
ipc_pm->host_pm_state, IPC_MEM_HOST_PM_SLEEP);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Sending Sleep Exit message to CP. Update the state */
|
||||
ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE_WAIT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep)
|
||||
{
|
||||
if (sleep) {
|
||||
ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP;
|
||||
ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP;
|
||||
ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_SLEEP;
|
||||
} else {
|
||||
ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
|
||||
ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
|
||||
ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_ACTIVE;
|
||||
ipc_pm->pm_cond.link = IPC_PM_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm, u32 cp_pm_req)
|
||||
{
|
||||
if (cp_pm_req == ipc_pm->device_sleep_notification)
|
||||
return false;
|
||||
|
||||
ipc_pm->device_sleep_notification = cp_pm_req;
|
||||
|
||||
/* Evaluate the PM request. */
|
||||
switch (ipc_pm->cp_state) {
|
||||
case IPC_MEM_DEV_PM_ACTIVE:
|
||||
switch (cp_pm_req) {
|
||||
case IPC_MEM_DEV_PM_ACTIVE:
|
||||
break;
|
||||
|
||||
case IPC_MEM_DEV_PM_SLEEP:
|
||||
/* Inform the PM that the device link can go down. */
|
||||
ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, false);
|
||||
return true;
|
||||
|
||||
default:
|
||||
dev_err(ipc_pm->dev,
|
||||
"loc-pm=%d active: confused req-pm=%d",
|
||||
ipc_pm->cp_state, cp_pm_req);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_MEM_DEV_PM_SLEEP:
|
||||
switch (cp_pm_req) {
|
||||
case IPC_MEM_DEV_PM_ACTIVE:
|
||||
/* Inform the PM that the device link is active. */
|
||||
ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, true);
|
||||
break;
|
||||
|
||||
case IPC_MEM_DEV_PM_SLEEP:
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ipc_pm->dev,
|
||||
"loc-pm=%d sleep: confused req-pm=%d",
|
||||
ipc_pm->cp_state, cp_pm_req);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ipc_pm->dev, "confused loc-pm=%d, req-pm=%d",
|
||||
ipc_pm->cp_state, cp_pm_req);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ipc_pm_init(struct iosm_protocol *ipc_protocol)
|
||||
{
|
||||
struct iosm_imem *ipc_imem = ipc_protocol->imem;
|
||||
struct iosm_pm *ipc_pm = &ipc_protocol->pm;
|
||||
|
||||
ipc_pm->pcie = ipc_imem->pcie;
|
||||
ipc_pm->dev = ipc_imem->dev;
|
||||
|
||||
ipc_pm->pm_cond.irq = IPC_PM_SLEEP;
|
||||
ipc_pm->pm_cond.hs = IPC_PM_SLEEP;
|
||||
ipc_pm->pm_cond.link = IPC_PM_ACTIVE;
|
||||
|
||||
ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
|
||||
ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
|
||||
ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
|
||||
|
||||
/* Create generic wait-for-completion handler for Host Sleep
|
||||
* and device sleep coordination.
|
||||
*/
|
||||
init_completion(&ipc_pm->host_sleep_complete);
|
||||
|
||||
/* Complete all memory stores before clearing bit */
|
||||
smp_mb__before_atomic();
|
||||
|
||||
clear_bit(0, &ipc_pm->host_sleep_pend);
|
||||
|
||||
/* Complete all memory stores after clearing bit */
|
||||
smp_mb__after_atomic();
|
||||
}
|
||||
|
||||
void ipc_pm_deinit(struct iosm_protocol *proto)
|
||||
{
|
||||
struct iosm_pm *ipc_pm = &proto->pm;
|
||||
|
||||
complete(&ipc_pm->host_sleep_complete);
|
||||
}
|
207
drivers/net/wwan/iosm/iosm_ipc_pm.h
Normal file
207
drivers/net/wwan/iosm/iosm_ipc_pm.h
Normal file
@ -0,0 +1,207 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2020-21 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef IOSM_IPC_PM_H
|
||||
#define IOSM_IPC_PM_H
|
||||
|
||||
/* Trigger the doorbell interrupt on cp to change the PM sleep/active status */
|
||||
#define ipc_cp_irq_sleep_control(ipc_pcie, data) \
|
||||
ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_SLEEP, data)
|
||||
|
||||
/* Trigger the doorbell interrupt on CP to do hpda update */
|
||||
#define ipc_cp_irq_hpda_update(ipc_pcie, data) \
|
||||
ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_HPDA, 0xFF & (data))
|
||||
|
||||
/**
|
||||
* union ipc_pm_cond - Conditions for D3 and the sleep message to CP.
|
||||
* @raw: raw/combined value for faster check
|
||||
* @irq: IRQ towards CP
|
||||
* @hs: Host Sleep
|
||||
* @link: Device link state.
|
||||
*/
|
||||
union ipc_pm_cond {
|
||||
unsigned int raw;
|
||||
|
||||
struct {
|
||||
unsigned int irq:1,
|
||||
hs:1,
|
||||
link:1;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ipc_mem_host_pm_state - Possible states of the HOST SLEEP finite state
|
||||
* machine.
|
||||
* @IPC_MEM_HOST_PM_ACTIVE: Host is active
|
||||
* @IPC_MEM_HOST_PM_ACTIVE_WAIT: Intermediate state before going to
|
||||
* active
|
||||
* @IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE: Intermediate state to wait for idle
|
||||
* before going into sleep
|
||||
* @IPC_MEM_HOST_PM_SLEEP_WAIT_D3: Intermediate state to wait for D3
|
||||
* before going to sleep
|
||||
* @IPC_MEM_HOST_PM_SLEEP: after this state the interface is not
|
||||
* accessible host is in suspend to RAM
|
||||
* @IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP: Intermediate state before exiting
|
||||
* sleep
|
||||
*/
|
||||
enum ipc_mem_host_pm_state {
|
||||
IPC_MEM_HOST_PM_ACTIVE,
|
||||
IPC_MEM_HOST_PM_ACTIVE_WAIT,
|
||||
IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE,
|
||||
IPC_MEM_HOST_PM_SLEEP_WAIT_D3,
|
||||
IPC_MEM_HOST_PM_SLEEP,
|
||||
IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ipc_mem_dev_pm_state - Possible states of the DEVICE SLEEP finite state
|
||||
* machine.
|
||||
* @IPC_MEM_DEV_PM_ACTIVE: IPC_MEM_DEV_PM_ACTIVE is the initial
|
||||
* power management state.
|
||||
* IRQ(struct ipc_mem_device_info:
|
||||
* device_sleep_notification)
|
||||
* and DOORBELL-IRQ-HPDA(data) values.
|
||||
* @IPC_MEM_DEV_PM_SLEEP: IPC_MEM_DEV_PM_SLEEP is PM state for
|
||||
* sleep.
|
||||
* @IPC_MEM_DEV_PM_WAKEUP: DOORBELL-IRQ-DEVICE_WAKE(data).
|
||||
* @IPC_MEM_DEV_PM_HOST_SLEEP: DOORBELL-IRQ-HOST_SLEEP(data).
|
||||
* @IPC_MEM_DEV_PM_ACTIVE_WAIT: Local intermediate states.
|
||||
* @IPC_MEM_DEV_PM_FORCE_SLEEP: DOORBELL-IRQ-FORCE_SLEEP.
|
||||
* @IPC_MEM_DEV_PM_FORCE_ACTIVE: DOORBELL-IRQ-FORCE_ACTIVE.
|
||||
*/
|
||||
enum ipc_mem_dev_pm_state {
|
||||
IPC_MEM_DEV_PM_ACTIVE,
|
||||
IPC_MEM_DEV_PM_SLEEP,
|
||||
IPC_MEM_DEV_PM_WAKEUP,
|
||||
IPC_MEM_DEV_PM_HOST_SLEEP,
|
||||
IPC_MEM_DEV_PM_ACTIVE_WAIT,
|
||||
IPC_MEM_DEV_PM_FORCE_SLEEP = 7,
|
||||
IPC_MEM_DEV_PM_FORCE_ACTIVE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_pm - Power management instance
|
||||
* @pcie: Pointer to iosm_pcie structure
|
||||
* @dev: Pointer to device structure
|
||||
* @host_pm_state: PM states for host
|
||||
* @host_sleep_pend: Variable to indicate Host Sleep Pending
|
||||
* @host_sleep_complete: Generic wait-for-completion used in
|
||||
* case of Host Sleep
|
||||
* @pm_cond: Conditions for power management
|
||||
* @ap_state: Current power management state, the
|
||||
* initial state is IPC_MEM_DEV_PM_ACTIVE eq. 0.
|
||||
* @cp_state: PM State of CP
|
||||
* @device_sleep_notification: last handled device_sleep_notfication
|
||||
* @pending_hpda_update: is a HPDA update pending?
|
||||
*/
|
||||
struct iosm_pm {
|
||||
struct iosm_pcie *pcie;
|
||||
struct device *dev;
|
||||
enum ipc_mem_host_pm_state host_pm_state;
|
||||
unsigned long host_sleep_pend;
|
||||
struct completion host_sleep_complete;
|
||||
union ipc_pm_cond pm_cond;
|
||||
enum ipc_mem_dev_pm_state ap_state;
|
||||
enum ipc_mem_dev_pm_state cp_state;
|
||||
u32 device_sleep_notification;
|
||||
u8 pending_hpda_update:1;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ipc_pm_unit - Power management units.
|
||||
* @IPC_PM_UNIT_IRQ: IRQ towards CP
|
||||
* @IPC_PM_UNIT_HS: Host Sleep for converged protocol
|
||||
* @IPC_PM_UNIT_LINK: Link state controlled by CP.
|
||||
*/
|
||||
enum ipc_pm_unit {
|
||||
IPC_PM_UNIT_IRQ,
|
||||
IPC_PM_UNIT_HS,
|
||||
IPC_PM_UNIT_LINK,
|
||||
};
|
||||
|
||||
/**
|
||||
* ipc_pm_init - Allocate power management component
|
||||
* @ipc_protocol: Pointer to iosm_protocol structure
|
||||
*/
|
||||
void ipc_pm_init(struct iosm_protocol *ipc_protocol);
|
||||
|
||||
/**
|
||||
* ipc_pm_deinit - Free power management component, invalidating its pointer.
|
||||
* @ipc_protocol: Pointer to iosm_protocol structure
|
||||
*/
|
||||
void ipc_pm_deinit(struct iosm_protocol *ipc_protocol);
|
||||
|
||||
/**
|
||||
* ipc_pm_dev_slp_notification - Handle a sleep notification message from the
|
||||
* device. This can be called from interrupt state
|
||||
* This function handles Host Sleep requests too
|
||||
* if the Host Sleep protocol is register based.
|
||||
* @ipc_pm: Pointer to power management component
|
||||
* @sleep_notification: Actual notification from device
|
||||
*
|
||||
* Returns: true if dev sleep state has to be checked, false otherwise.
|
||||
*/
|
||||
bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm,
|
||||
u32 sleep_notification);
|
||||
|
||||
/**
|
||||
* ipc_pm_set_s2idle_sleep - Set PM variables to sleep/active
|
||||
* @ipc_pm: Pointer to power management component
|
||||
* @sleep: true to enter sleep/false to exit sleep
|
||||
*/
|
||||
void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep);
|
||||
|
||||
/**
|
||||
* ipc_pm_prepare_host_sleep - Prepare the PM for sleep by entering
|
||||
* IPC_MEM_HOST_PM_SLEEP_WAIT_D3 state.
|
||||
* @ipc_pm: Pointer to power management component
|
||||
*
|
||||
* Returns: true on success, false if the host was not active.
|
||||
*/
|
||||
bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm);
|
||||
|
||||
/**
|
||||
* ipc_pm_prepare_host_active - Prepare the PM for wakeup by entering
|
||||
* IPC_MEM_HOST_PM_ACTIVE_WAIT state.
|
||||
* @ipc_pm: Pointer to power management component
|
||||
*
|
||||
* Returns: true on success, false if the host was not sleeping.
|
||||
*/
|
||||
bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm);
|
||||
|
||||
/**
|
||||
* ipc_pm_wait_for_device_active - Wait upto IPC_PM_ACTIVE_TIMEOUT_MS ms
|
||||
* for the device to reach active state
|
||||
* @ipc_pm: Pointer to power management component
|
||||
*
|
||||
* Returns: true if device is active, false on timeout
|
||||
*/
|
||||
bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm);
|
||||
|
||||
/**
|
||||
* ipc_pm_signal_hpda_doorbell - Wake up the device if it is in low power mode
|
||||
* and trigger a head pointer update interrupt.
|
||||
* @ipc_pm: Pointer to power management component
|
||||
* @identifier: specifies what component triggered hpda update irq
|
||||
* @host_slp_check: if set to true then Host Sleep state machine check will
|
||||
* be performed. If Host Sleep state machine allows HP
|
||||
* update then only doorbell is triggered otherwise pending
|
||||
* flag will be set. If set to false then Host Sleep check
|
||||
* will not be performed. This is helpful for Host Sleep
|
||||
* negotiation through message ring.
|
||||
*/
|
||||
void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
|
||||
bool host_slp_check);
|
||||
/**
|
||||
* ipc_pm_trigger - Update power manager and wake up the link if needed
|
||||
* @ipc_pm: Pointer to power management component
|
||||
* @unit: Power management units
|
||||
* @active: Device link state
|
||||
*
|
||||
* Returns: true if link is unchanged or active, false otherwise
|
||||
*/
|
||||
bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user