208 lines
6.8 KiB
C
208 lines
6.8 KiB
C
|
/* 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
|