1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020-21 Intel Corporation. 4 */ 5 6 #include "iosm_ipc_protocol.h" 7 8 /* Timeout value in MS for the PM to wait for device to reach active state */ 9 #define IPC_PM_ACTIVE_TIMEOUT_MS (500) 10 11 /* Note that here "active" has the value 1, as compared to the enums 12 * ipc_mem_host_pm_state or ipc_mem_dev_pm_state, where "active" is 0 13 */ 14 #define IPC_PM_SLEEP (0) 15 #define CONSUME_STATE (0) 16 #define IPC_PM_ACTIVE (1) 17 18 void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier, 19 bool host_slp_check) 20 { 21 if (host_slp_check && ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE && 22 ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE_WAIT) { 23 ipc_pm->pending_hpda_update = true; 24 dev_dbg(ipc_pm->dev, 25 "Pend HPDA update set. Host PM_State: %d identifier:%d", 26 ipc_pm->host_pm_state, identifier); 27 return; 28 } 29 30 if (!ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, true)) { 31 ipc_pm->pending_hpda_update = true; 32 dev_dbg(ipc_pm->dev, "Pending HPDA update set. identifier:%d", 33 identifier); 34 return; 35 } 36 ipc_pm->pending_hpda_update = false; 37 38 /* Trigger the irq towards CP */ 39 ipc_cp_irq_hpda_update(ipc_pm->pcie, identifier); 40 41 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, false); 42 } 43 44 /* Wake up the device if it is in low power mode. */ 45 static bool ipc_pm_link_activate(struct iosm_pm *ipc_pm) 46 { 47 if (ipc_pm->cp_state == IPC_MEM_DEV_PM_ACTIVE) 48 return true; 49 50 if (ipc_pm->cp_state == IPC_MEM_DEV_PM_SLEEP) { 51 if (ipc_pm->ap_state == IPC_MEM_DEV_PM_SLEEP) { 52 /* Wake up the device. */ 53 ipc_cp_irq_sleep_control(ipc_pm->pcie, 54 IPC_MEM_DEV_PM_WAKEUP); 55 ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE_WAIT; 56 57 goto not_active; 58 } 59 60 if (ipc_pm->ap_state == IPC_MEM_DEV_PM_ACTIVE_WAIT) 61 goto not_active; 62 63 return true; 64 } 65 66 not_active: 67 /* link is not ready */ 68 return false; 69 } 70 71 bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm) 72 { 73 bool ret_val = false; 74 75 if (ipc_pm->ap_state != IPC_MEM_DEV_PM_ACTIVE) { 76 /* Complete all memory stores before setting bit */ 77 smp_mb__before_atomic(); 78 79 /* Wait for IPC_PM_ACTIVE_TIMEOUT_MS for Device sleep state 80 * machine to enter ACTIVE state. 81 */ 82 set_bit(0, &ipc_pm->host_sleep_pend); 83 84 /* Complete all memory stores after setting bit */ 85 smp_mb__after_atomic(); 86 87 if (!wait_for_completion_interruptible_timeout 88 (&ipc_pm->host_sleep_complete, 89 msecs_to_jiffies(IPC_PM_ACTIVE_TIMEOUT_MS))) { 90 dev_err(ipc_pm->dev, 91 "PM timeout. Expected State:%d. Actual: %d", 92 IPC_MEM_DEV_PM_ACTIVE, ipc_pm->ap_state); 93 goto active_timeout; 94 } 95 } 96 97 ret_val = true; 98 active_timeout: 99 /* Complete all memory stores before clearing bit */ 100 smp_mb__before_atomic(); 101 102 /* Reset the atomic variable in any case as device sleep 103 * state machine change is no longer of interest. 104 */ 105 clear_bit(0, &ipc_pm->host_sleep_pend); 106 107 /* Complete all memory stores after clearing bit */ 108 smp_mb__after_atomic(); 109 110 return ret_val; 111 } 112 113 static void ipc_pm_on_link_sleep(struct iosm_pm *ipc_pm) 114 { 115 /* pending sleep ack and all conditions are cleared 116 * -> signal SLEEP__ACK to CP 117 */ 118 ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP; 119 ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP; 120 121 ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_SLEEP); 122 } 123 124 static void ipc_pm_on_link_wake(struct iosm_pm *ipc_pm, bool ack) 125 { 126 ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE; 127 128 if (ack) { 129 ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE; 130 131 ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_ACTIVE); 132 133 /* check the consume state !!! */ 134 if (test_bit(CONSUME_STATE, &ipc_pm->host_sleep_pend)) 135 complete(&ipc_pm->host_sleep_complete); 136 } 137 138 /* Check for pending HPDA update. 139 * Pending HP update could be because of sending message was 140 * put on hold due to Device sleep state or due to TD update 141 * which could be because of Device Sleep and Host Sleep 142 * states. 143 */ 144 if (ipc_pm->pending_hpda_update && 145 ipc_pm->host_pm_state == IPC_MEM_HOST_PM_ACTIVE) 146 ipc_pm_signal_hpda_doorbell(ipc_pm, IPC_HP_PM_TRIGGER, true); 147 } 148 149 bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active) 150 { 151 union ipc_pm_cond old_cond; 152 union ipc_pm_cond new_cond; 153 bool link_active; 154 155 /* Save the current D3 state. */ 156 new_cond = ipc_pm->pm_cond; 157 old_cond = ipc_pm->pm_cond; 158 159 /* Calculate the power state only in the runtime phase. */ 160 switch (unit) { 161 case IPC_PM_UNIT_IRQ: /* CP irq */ 162 new_cond.irq = active; 163 break; 164 165 case IPC_PM_UNIT_LINK: /* Device link state. */ 166 new_cond.link = active; 167 break; 168 169 case IPC_PM_UNIT_HS: /* Host sleep trigger requires Link. */ 170 new_cond.hs = active; 171 break; 172 173 default: 174 break; 175 } 176 177 /* Something changed ? */ 178 if (old_cond.raw == new_cond.raw) { 179 /* Stay in the current PM state. */ 180 link_active = old_cond.link == IPC_PM_ACTIVE; 181 goto ret; 182 } 183 184 ipc_pm->pm_cond = new_cond; 185 186 if (new_cond.link) 187 ipc_pm_on_link_wake(ipc_pm, unit == IPC_PM_UNIT_LINK); 188 else if (unit == IPC_PM_UNIT_LINK) 189 ipc_pm_on_link_sleep(ipc_pm); 190 191 if (old_cond.link == IPC_PM_SLEEP && new_cond.raw) { 192 link_active = ipc_pm_link_activate(ipc_pm); 193 goto ret; 194 } 195 196 link_active = old_cond.link == IPC_PM_ACTIVE; 197 198 ret: 199 return link_active; 200 } 201 202 bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm) 203 { 204 /* suspend not allowed if host_pm_state is not IPC_MEM_HOST_PM_ACTIVE */ 205 if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE) { 206 dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d", 207 ipc_pm->host_pm_state, IPC_MEM_HOST_PM_ACTIVE); 208 return false; 209 } 210 211 ipc_pm->host_pm_state = IPC_MEM_HOST_PM_SLEEP_WAIT_D3; 212 213 return true; 214 } 215 216 bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm) 217 { 218 if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_SLEEP) { 219 dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d", 220 ipc_pm->host_pm_state, IPC_MEM_HOST_PM_SLEEP); 221 return false; 222 } 223 224 /* Sending Sleep Exit message to CP. Update the state */ 225 ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE_WAIT; 226 227 return true; 228 } 229 230 void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep) 231 { 232 if (sleep) { 233 ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP; 234 ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP; 235 ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_SLEEP; 236 } else { 237 ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE; 238 ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE; 239 ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_ACTIVE; 240 ipc_pm->pm_cond.link = IPC_PM_ACTIVE; 241 } 242 } 243 244 bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm, u32 cp_pm_req) 245 { 246 if (cp_pm_req == ipc_pm->device_sleep_notification) 247 return false; 248 249 ipc_pm->device_sleep_notification = cp_pm_req; 250 251 /* Evaluate the PM request. */ 252 switch (ipc_pm->cp_state) { 253 case IPC_MEM_DEV_PM_ACTIVE: 254 switch (cp_pm_req) { 255 case IPC_MEM_DEV_PM_ACTIVE: 256 break; 257 258 case IPC_MEM_DEV_PM_SLEEP: 259 /* Inform the PM that the device link can go down. */ 260 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, false); 261 return true; 262 263 default: 264 dev_err(ipc_pm->dev, 265 "loc-pm=%d active: confused req-pm=%d", 266 ipc_pm->cp_state, cp_pm_req); 267 break; 268 } 269 break; 270 271 case IPC_MEM_DEV_PM_SLEEP: 272 switch (cp_pm_req) { 273 case IPC_MEM_DEV_PM_ACTIVE: 274 /* Inform the PM that the device link is active. */ 275 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, true); 276 break; 277 278 case IPC_MEM_DEV_PM_SLEEP: 279 break; 280 281 default: 282 dev_err(ipc_pm->dev, 283 "loc-pm=%d sleep: confused req-pm=%d", 284 ipc_pm->cp_state, cp_pm_req); 285 break; 286 } 287 break; 288 289 default: 290 dev_err(ipc_pm->dev, "confused loc-pm=%d, req-pm=%d", 291 ipc_pm->cp_state, cp_pm_req); 292 break; 293 } 294 295 return false; 296 } 297 298 void ipc_pm_init(struct iosm_protocol *ipc_protocol) 299 { 300 struct iosm_imem *ipc_imem = ipc_protocol->imem; 301 struct iosm_pm *ipc_pm = &ipc_protocol->pm; 302 303 ipc_pm->pcie = ipc_imem->pcie; 304 ipc_pm->dev = ipc_imem->dev; 305 306 ipc_pm->pm_cond.irq = IPC_PM_SLEEP; 307 ipc_pm->pm_cond.hs = IPC_PM_SLEEP; 308 ipc_pm->pm_cond.link = IPC_PM_ACTIVE; 309 310 ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE; 311 ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE; 312 ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE; 313 314 /* Create generic wait-for-completion handler for Host Sleep 315 * and device sleep coordination. 316 */ 317 init_completion(&ipc_pm->host_sleep_complete); 318 319 /* Complete all memory stores before clearing bit */ 320 smp_mb__before_atomic(); 321 322 clear_bit(0, &ipc_pm->host_sleep_pend); 323 324 /* Complete all memory stores after clearing bit */ 325 smp_mb__after_atomic(); 326 } 327 328 void ipc_pm_deinit(struct iosm_protocol *proto) 329 { 330 struct iosm_pm *ipc_pm = &proto->pm; 331 332 complete(&ipc_pm->host_sleep_complete); 333 } 334