1 /* SPDX-License-Identifier: GPL-2.0-only 2 * 3 * Copyright (C) 2020-21 Intel Corporation. 4 */ 5 6 #ifndef IOSM_IPC_PM_H 7 #define IOSM_IPC_PM_H 8 9 /* Trigger the doorbell interrupt on cp to change the PM sleep/active status */ 10 #define ipc_cp_irq_sleep_control(ipc_pcie, data) \ 11 ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_SLEEP, data) 12 13 /* Trigger the doorbell interrupt on CP to do hpda update */ 14 #define ipc_cp_irq_hpda_update(ipc_pcie, data) \ 15 ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_HPDA, 0xFF & (data)) 16 17 /** 18 * union ipc_pm_cond - Conditions for D3 and the sleep message to CP. 19 * @raw: raw/combined value for faster check 20 * @irq: IRQ towards CP 21 * @hs: Host Sleep 22 * @link: Device link state. 23 */ 24 union ipc_pm_cond { 25 unsigned int raw; 26 27 struct { 28 unsigned int irq:1, 29 hs:1, 30 link:1; 31 }; 32 }; 33 34 /** 35 * enum ipc_mem_host_pm_state - Possible states of the HOST SLEEP finite state 36 * machine. 37 * @IPC_MEM_HOST_PM_ACTIVE: Host is active 38 * @IPC_MEM_HOST_PM_ACTIVE_WAIT: Intermediate state before going to 39 * active 40 * @IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE: Intermediate state to wait for idle 41 * before going into sleep 42 * @IPC_MEM_HOST_PM_SLEEP_WAIT_D3: Intermediate state to wait for D3 43 * before going to sleep 44 * @IPC_MEM_HOST_PM_SLEEP: after this state the interface is not 45 * accessible host is in suspend to RAM 46 * @IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP: Intermediate state before exiting 47 * sleep 48 */ 49 enum ipc_mem_host_pm_state { 50 IPC_MEM_HOST_PM_ACTIVE, 51 IPC_MEM_HOST_PM_ACTIVE_WAIT, 52 IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE, 53 IPC_MEM_HOST_PM_SLEEP_WAIT_D3, 54 IPC_MEM_HOST_PM_SLEEP, 55 IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP, 56 }; 57 58 /** 59 * enum ipc_mem_dev_pm_state - Possible states of the DEVICE SLEEP finite state 60 * machine. 61 * @IPC_MEM_DEV_PM_ACTIVE: IPC_MEM_DEV_PM_ACTIVE is the initial 62 * power management state. 63 * IRQ(struct ipc_mem_device_info: 64 * device_sleep_notification) 65 * and DOORBELL-IRQ-HPDA(data) values. 66 * @IPC_MEM_DEV_PM_SLEEP: IPC_MEM_DEV_PM_SLEEP is PM state for 67 * sleep. 68 * @IPC_MEM_DEV_PM_WAKEUP: DOORBELL-IRQ-DEVICE_WAKE(data). 69 * @IPC_MEM_DEV_PM_HOST_SLEEP: DOORBELL-IRQ-HOST_SLEEP(data). 70 * @IPC_MEM_DEV_PM_ACTIVE_WAIT: Local intermediate states. 71 * @IPC_MEM_DEV_PM_FORCE_SLEEP: DOORBELL-IRQ-FORCE_SLEEP. 72 * @IPC_MEM_DEV_PM_FORCE_ACTIVE: DOORBELL-IRQ-FORCE_ACTIVE. 73 */ 74 enum ipc_mem_dev_pm_state { 75 IPC_MEM_DEV_PM_ACTIVE, 76 IPC_MEM_DEV_PM_SLEEP, 77 IPC_MEM_DEV_PM_WAKEUP, 78 IPC_MEM_DEV_PM_HOST_SLEEP, 79 IPC_MEM_DEV_PM_ACTIVE_WAIT, 80 IPC_MEM_DEV_PM_FORCE_SLEEP = 7, 81 IPC_MEM_DEV_PM_FORCE_ACTIVE, 82 }; 83 84 /** 85 * struct iosm_pm - Power management instance 86 * @pcie: Pointer to iosm_pcie structure 87 * @dev: Pointer to device structure 88 * @host_pm_state: PM states for host 89 * @host_sleep_pend: Variable to indicate Host Sleep Pending 90 * @host_sleep_complete: Generic wait-for-completion used in 91 * case of Host Sleep 92 * @pm_cond: Conditions for power management 93 * @ap_state: Current power management state, the 94 * initial state is IPC_MEM_DEV_PM_ACTIVE eq. 0. 95 * @cp_state: PM State of CP 96 * @device_sleep_notification: last handled device_sleep_notfication 97 * @pending_hpda_update: is a HPDA update pending? 98 */ 99 struct iosm_pm { 100 struct iosm_pcie *pcie; 101 struct device *dev; 102 enum ipc_mem_host_pm_state host_pm_state; 103 unsigned long host_sleep_pend; 104 struct completion host_sleep_complete; 105 union ipc_pm_cond pm_cond; 106 enum ipc_mem_dev_pm_state ap_state; 107 enum ipc_mem_dev_pm_state cp_state; 108 u32 device_sleep_notification; 109 u8 pending_hpda_update:1; 110 }; 111 112 /** 113 * enum ipc_pm_unit - Power management units. 114 * @IPC_PM_UNIT_IRQ: IRQ towards CP 115 * @IPC_PM_UNIT_HS: Host Sleep for converged protocol 116 * @IPC_PM_UNIT_LINK: Link state controlled by CP. 117 */ 118 enum ipc_pm_unit { 119 IPC_PM_UNIT_IRQ, 120 IPC_PM_UNIT_HS, 121 IPC_PM_UNIT_LINK, 122 }; 123 124 /** 125 * ipc_pm_init - Allocate power management component 126 * @ipc_protocol: Pointer to iosm_protocol structure 127 */ 128 void ipc_pm_init(struct iosm_protocol *ipc_protocol); 129 130 /** 131 * ipc_pm_deinit - Free power management component, invalidating its pointer. 132 * @ipc_protocol: Pointer to iosm_protocol structure 133 */ 134 void ipc_pm_deinit(struct iosm_protocol *ipc_protocol); 135 136 /** 137 * ipc_pm_dev_slp_notification - Handle a sleep notification message from the 138 * device. This can be called from interrupt state 139 * This function handles Host Sleep requests too 140 * if the Host Sleep protocol is register based. 141 * @ipc_pm: Pointer to power management component 142 * @sleep_notification: Actual notification from device 143 * 144 * Returns: true if dev sleep state has to be checked, false otherwise. 145 */ 146 bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm, 147 u32 sleep_notification); 148 149 /** 150 * ipc_pm_set_s2idle_sleep - Set PM variables to sleep/active 151 * @ipc_pm: Pointer to power management component 152 * @sleep: true to enter sleep/false to exit sleep 153 */ 154 void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep); 155 156 /** 157 * ipc_pm_prepare_host_sleep - Prepare the PM for sleep by entering 158 * IPC_MEM_HOST_PM_SLEEP_WAIT_D3 state. 159 * @ipc_pm: Pointer to power management component 160 * 161 * Returns: true on success, false if the host was not active. 162 */ 163 bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm); 164 165 /** 166 * ipc_pm_prepare_host_active - Prepare the PM for wakeup by entering 167 * IPC_MEM_HOST_PM_ACTIVE_WAIT state. 168 * @ipc_pm: Pointer to power management component 169 * 170 * Returns: true on success, false if the host was not sleeping. 171 */ 172 bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm); 173 174 /** 175 * ipc_pm_wait_for_device_active - Wait upto IPC_PM_ACTIVE_TIMEOUT_MS ms 176 * for the device to reach active state 177 * @ipc_pm: Pointer to power management component 178 * 179 * Returns: true if device is active, false on timeout 180 */ 181 bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm); 182 183 /** 184 * ipc_pm_signal_hpda_doorbell - Wake up the device if it is in low power mode 185 * and trigger a head pointer update interrupt. 186 * @ipc_pm: Pointer to power management component 187 * @identifier: specifies what component triggered hpda update irq 188 * @host_slp_check: if set to true then Host Sleep state machine check will 189 * be performed. If Host Sleep state machine allows HP 190 * update then only doorbell is triggered otherwise pending 191 * flag will be set. If set to false then Host Sleep check 192 * will not be performed. This is helpful for Host Sleep 193 * negotiation through message ring. 194 */ 195 void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier, 196 bool host_slp_check); 197 /** 198 * ipc_pm_trigger - Update power manager and wake up the link if needed 199 * @ipc_pm: Pointer to power management component 200 * @unit: Power management units 201 * @active: Device link state 202 * 203 * Returns: true if link is unchanged or active, false otherwise 204 */ 205 bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active); 206 207 #endif 208