mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
6.8 KiB
207 lines
6.8 KiB
/* 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
|
|
|