162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright (C) 2020-21 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef IOSM_IPC_PM_H 762306a36Sopenharmony_ci#define IOSM_IPC_PM_H 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* Trigger the doorbell interrupt on cp to change the PM sleep/active status */ 1062306a36Sopenharmony_ci#define ipc_cp_irq_sleep_control(ipc_pcie, data) \ 1162306a36Sopenharmony_ci ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_SLEEP, data) 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* Trigger the doorbell interrupt on CP to do hpda update */ 1462306a36Sopenharmony_ci#define ipc_cp_irq_hpda_update(ipc_pcie, data) \ 1562306a36Sopenharmony_ci ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_HPDA, 0xFF & (data)) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/** 1862306a36Sopenharmony_ci * union ipc_pm_cond - Conditions for D3 and the sleep message to CP. 1962306a36Sopenharmony_ci * @raw: raw/combined value for faster check 2062306a36Sopenharmony_ci * @irq: IRQ towards CP 2162306a36Sopenharmony_ci * @hs: Host Sleep 2262306a36Sopenharmony_ci * @link: Device link state. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ciunion ipc_pm_cond { 2562306a36Sopenharmony_ci unsigned int raw; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci struct { 2862306a36Sopenharmony_ci unsigned int irq:1, 2962306a36Sopenharmony_ci hs:1, 3062306a36Sopenharmony_ci link:1; 3162306a36Sopenharmony_ci }; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/** 3562306a36Sopenharmony_ci * enum ipc_mem_host_pm_state - Possible states of the HOST SLEEP finite state 3662306a36Sopenharmony_ci * machine. 3762306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_ACTIVE: Host is active 3862306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_ACTIVE_WAIT: Intermediate state before going to 3962306a36Sopenharmony_ci * active 4062306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE: Intermediate state to wait for idle 4162306a36Sopenharmony_ci * before going into sleep 4262306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP_WAIT_D3: Intermediate state to wait for D3 4362306a36Sopenharmony_ci * before going to sleep 4462306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP: after this state the interface is not 4562306a36Sopenharmony_ci * accessible host is in suspend to RAM 4662306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP: Intermediate state before exiting 4762306a36Sopenharmony_ci * sleep 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cienum ipc_mem_host_pm_state { 5062306a36Sopenharmony_ci IPC_MEM_HOST_PM_ACTIVE, 5162306a36Sopenharmony_ci IPC_MEM_HOST_PM_ACTIVE_WAIT, 5262306a36Sopenharmony_ci IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE, 5362306a36Sopenharmony_ci IPC_MEM_HOST_PM_SLEEP_WAIT_D3, 5462306a36Sopenharmony_ci IPC_MEM_HOST_PM_SLEEP, 5562306a36Sopenharmony_ci IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP, 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * enum ipc_mem_dev_pm_state - Possible states of the DEVICE SLEEP finite state 6062306a36Sopenharmony_ci * machine. 6162306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_ACTIVE: IPC_MEM_DEV_PM_ACTIVE is the initial 6262306a36Sopenharmony_ci * power management state. 6362306a36Sopenharmony_ci * IRQ(struct ipc_mem_device_info: 6462306a36Sopenharmony_ci * device_sleep_notification) 6562306a36Sopenharmony_ci * and DOORBELL-IRQ-HPDA(data) values. 6662306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_SLEEP: IPC_MEM_DEV_PM_SLEEP is PM state for 6762306a36Sopenharmony_ci * sleep. 6862306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_WAKEUP: DOORBELL-IRQ-DEVICE_WAKE(data). 6962306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_HOST_SLEEP: DOORBELL-IRQ-HOST_SLEEP(data). 7062306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_ACTIVE_WAIT: Local intermediate states. 7162306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_FORCE_SLEEP: DOORBELL-IRQ-FORCE_SLEEP. 7262306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_FORCE_ACTIVE: DOORBELL-IRQ-FORCE_ACTIVE. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cienum ipc_mem_dev_pm_state { 7562306a36Sopenharmony_ci IPC_MEM_DEV_PM_ACTIVE, 7662306a36Sopenharmony_ci IPC_MEM_DEV_PM_SLEEP, 7762306a36Sopenharmony_ci IPC_MEM_DEV_PM_WAKEUP, 7862306a36Sopenharmony_ci IPC_MEM_DEV_PM_HOST_SLEEP, 7962306a36Sopenharmony_ci IPC_MEM_DEV_PM_ACTIVE_WAIT, 8062306a36Sopenharmony_ci IPC_MEM_DEV_PM_FORCE_SLEEP = 7, 8162306a36Sopenharmony_ci IPC_MEM_DEV_PM_FORCE_ACTIVE, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/** 8562306a36Sopenharmony_ci * struct iosm_pm - Power management instance 8662306a36Sopenharmony_ci * @pcie: Pointer to iosm_pcie structure 8762306a36Sopenharmony_ci * @dev: Pointer to device structure 8862306a36Sopenharmony_ci * @host_pm_state: PM states for host 8962306a36Sopenharmony_ci * @host_sleep_pend: Variable to indicate Host Sleep Pending 9062306a36Sopenharmony_ci * @host_sleep_complete: Generic wait-for-completion used in 9162306a36Sopenharmony_ci * case of Host Sleep 9262306a36Sopenharmony_ci * @pm_cond: Conditions for power management 9362306a36Sopenharmony_ci * @ap_state: Current power management state, the 9462306a36Sopenharmony_ci * initial state is IPC_MEM_DEV_PM_ACTIVE eq. 0. 9562306a36Sopenharmony_ci * @cp_state: PM State of CP 9662306a36Sopenharmony_ci * @device_sleep_notification: last handled device_sleep_notfication 9762306a36Sopenharmony_ci * @pending_hpda_update: is a HPDA update pending? 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_cistruct iosm_pm { 10062306a36Sopenharmony_ci struct iosm_pcie *pcie; 10162306a36Sopenharmony_ci struct device *dev; 10262306a36Sopenharmony_ci enum ipc_mem_host_pm_state host_pm_state; 10362306a36Sopenharmony_ci unsigned long host_sleep_pend; 10462306a36Sopenharmony_ci struct completion host_sleep_complete; 10562306a36Sopenharmony_ci union ipc_pm_cond pm_cond; 10662306a36Sopenharmony_ci enum ipc_mem_dev_pm_state ap_state; 10762306a36Sopenharmony_ci enum ipc_mem_dev_pm_state cp_state; 10862306a36Sopenharmony_ci u32 device_sleep_notification; 10962306a36Sopenharmony_ci u8 pending_hpda_update:1; 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/** 11362306a36Sopenharmony_ci * enum ipc_pm_unit - Power management units. 11462306a36Sopenharmony_ci * @IPC_PM_UNIT_IRQ: IRQ towards CP 11562306a36Sopenharmony_ci * @IPC_PM_UNIT_HS: Host Sleep for converged protocol 11662306a36Sopenharmony_ci * @IPC_PM_UNIT_LINK: Link state controlled by CP. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_cienum ipc_pm_unit { 11962306a36Sopenharmony_ci IPC_PM_UNIT_IRQ, 12062306a36Sopenharmony_ci IPC_PM_UNIT_HS, 12162306a36Sopenharmony_ci IPC_PM_UNIT_LINK, 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * ipc_pm_init - Allocate power management component 12662306a36Sopenharmony_ci * @ipc_protocol: Pointer to iosm_protocol structure 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_civoid ipc_pm_init(struct iosm_protocol *ipc_protocol); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/** 13162306a36Sopenharmony_ci * ipc_pm_deinit - Free power management component, invalidating its pointer. 13262306a36Sopenharmony_ci * @ipc_protocol: Pointer to iosm_protocol structure 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_civoid ipc_pm_deinit(struct iosm_protocol *ipc_protocol); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * ipc_pm_dev_slp_notification - Handle a sleep notification message from the 13862306a36Sopenharmony_ci * device. This can be called from interrupt state 13962306a36Sopenharmony_ci * This function handles Host Sleep requests too 14062306a36Sopenharmony_ci * if the Host Sleep protocol is register based. 14162306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 14262306a36Sopenharmony_ci * @sleep_notification: Actual notification from device 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Returns: true if dev sleep state has to be checked, false otherwise. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cibool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm, 14762306a36Sopenharmony_ci u32 sleep_notification); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/** 15062306a36Sopenharmony_ci * ipc_pm_set_s2idle_sleep - Set PM variables to sleep/active 15162306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 15262306a36Sopenharmony_ci * @sleep: true to enter sleep/false to exit sleep 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_civoid ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/** 15762306a36Sopenharmony_ci * ipc_pm_prepare_host_sleep - Prepare the PM for sleep by entering 15862306a36Sopenharmony_ci * IPC_MEM_HOST_PM_SLEEP_WAIT_D3 state. 15962306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Returns: true on success, false if the host was not active. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cibool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * ipc_pm_prepare_host_active - Prepare the PM for wakeup by entering 16762306a36Sopenharmony_ci * IPC_MEM_HOST_PM_ACTIVE_WAIT state. 16862306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * Returns: true on success, false if the host was not sleeping. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_cibool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * ipc_pm_wait_for_device_active - Wait upto IPC_PM_ACTIVE_TIMEOUT_MS ms 17662306a36Sopenharmony_ci * for the device to reach active state 17762306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * Returns: true if device is active, false on timeout 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cibool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/** 18462306a36Sopenharmony_ci * ipc_pm_signal_hpda_doorbell - Wake up the device if it is in low power mode 18562306a36Sopenharmony_ci * and trigger a head pointer update interrupt. 18662306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 18762306a36Sopenharmony_ci * @identifier: specifies what component triggered hpda update irq 18862306a36Sopenharmony_ci * @host_slp_check: if set to true then Host Sleep state machine check will 18962306a36Sopenharmony_ci * be performed. If Host Sleep state machine allows HP 19062306a36Sopenharmony_ci * update then only doorbell is triggered otherwise pending 19162306a36Sopenharmony_ci * flag will be set. If set to false then Host Sleep check 19262306a36Sopenharmony_ci * will not be performed. This is helpful for Host Sleep 19362306a36Sopenharmony_ci * negotiation through message ring. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_civoid ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier, 19662306a36Sopenharmony_ci bool host_slp_check); 19762306a36Sopenharmony_ci/** 19862306a36Sopenharmony_ci * ipc_pm_trigger - Update power manager and wake up the link if needed 19962306a36Sopenharmony_ci * @ipc_pm: Pointer to power management component 20062306a36Sopenharmony_ci * @unit: Power management units 20162306a36Sopenharmony_ci * @active: Device link state 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Returns: true if link is unchanged or active, false otherwise 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cibool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#endif 208