Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 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 |