Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020-21 Intel Corporation.
0004  */
0005 
0006 #include "iosm_ipc_protocol.h"
0007 
0008 /* Timeout value in MS for the PM to wait for device to reach active state */
0009 #define IPC_PM_ACTIVE_TIMEOUT_MS (500)
0010 
0011 /* Note that here "active" has the value 1, as compared to the enums
0012  * ipc_mem_host_pm_state or ipc_mem_dev_pm_state, where "active" is 0
0013  */
0014 #define IPC_PM_SLEEP (0)
0015 #define CONSUME_STATE (0)
0016 #define IPC_PM_ACTIVE (1)
0017 
0018 void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
0019                  bool host_slp_check)
0020 {
0021     if (host_slp_check && ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE &&
0022         ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE_WAIT) {
0023         ipc_pm->pending_hpda_update = true;
0024         dev_dbg(ipc_pm->dev,
0025             "Pend HPDA update set. Host PM_State: %d identifier:%d",
0026             ipc_pm->host_pm_state, identifier);
0027         return;
0028     }
0029 
0030     if (!ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, true)) {
0031         ipc_pm->pending_hpda_update = true;
0032         dev_dbg(ipc_pm->dev, "Pending HPDA update set. identifier:%d",
0033             identifier);
0034         return;
0035     }
0036     ipc_pm->pending_hpda_update = false;
0037 
0038     /* Trigger the irq towards CP */
0039     ipc_cp_irq_hpda_update(ipc_pm->pcie, identifier);
0040 
0041     ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, false);
0042 }
0043 
0044 /* Wake up the device if it is in low power mode. */
0045 static bool ipc_pm_link_activate(struct iosm_pm *ipc_pm)
0046 {
0047     if (ipc_pm->cp_state == IPC_MEM_DEV_PM_ACTIVE)
0048         return true;
0049 
0050     if (ipc_pm->cp_state == IPC_MEM_DEV_PM_SLEEP) {
0051         if (ipc_pm->ap_state == IPC_MEM_DEV_PM_SLEEP) {
0052             /* Wake up the device. */
0053             ipc_cp_irq_sleep_control(ipc_pm->pcie,
0054                          IPC_MEM_DEV_PM_WAKEUP);
0055             ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE_WAIT;
0056 
0057             goto not_active;
0058         }
0059 
0060         if (ipc_pm->ap_state == IPC_MEM_DEV_PM_ACTIVE_WAIT)
0061             goto not_active;
0062 
0063         return true;
0064     }
0065 
0066 not_active:
0067     /* link is not ready */
0068     return false;
0069 }
0070 
0071 bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm)
0072 {
0073     bool ret_val = false;
0074 
0075     if (ipc_pm->ap_state != IPC_MEM_DEV_PM_ACTIVE) {
0076         /* Complete all memory stores before setting bit */
0077         smp_mb__before_atomic();
0078 
0079         /* Wait for IPC_PM_ACTIVE_TIMEOUT_MS for Device sleep state
0080          * machine to enter ACTIVE state.
0081          */
0082         set_bit(0, &ipc_pm->host_sleep_pend);
0083 
0084         /* Complete all memory stores after setting bit */
0085         smp_mb__after_atomic();
0086 
0087         if (!wait_for_completion_interruptible_timeout
0088            (&ipc_pm->host_sleep_complete,
0089             msecs_to_jiffies(IPC_PM_ACTIVE_TIMEOUT_MS))) {
0090             dev_err(ipc_pm->dev,
0091                 "PM timeout. Expected State:%d. Actual: %d",
0092                 IPC_MEM_DEV_PM_ACTIVE, ipc_pm->ap_state);
0093             goto  active_timeout;
0094         }
0095     }
0096 
0097     ret_val = true;
0098 active_timeout:
0099     /* Complete all memory stores before clearing bit */
0100     smp_mb__before_atomic();
0101 
0102     /* Reset the atomic variable in any case as device sleep
0103      * state machine change is no longer of interest.
0104      */
0105     clear_bit(0, &ipc_pm->host_sleep_pend);
0106 
0107     /* Complete all memory stores after clearing bit */
0108     smp_mb__after_atomic();
0109 
0110     return ret_val;
0111 }
0112 
0113 static void ipc_pm_on_link_sleep(struct iosm_pm *ipc_pm)
0114 {
0115     /* pending sleep ack and all conditions are cleared
0116      * -> signal SLEEP__ACK to CP
0117      */
0118     ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP;
0119     ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP;
0120 
0121     ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_SLEEP);
0122 }
0123 
0124 static void ipc_pm_on_link_wake(struct iosm_pm *ipc_pm, bool ack)
0125 {
0126     ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
0127 
0128     if (ack) {
0129         ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
0130 
0131         ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_ACTIVE);
0132 
0133         /* check the consume state !!! */
0134         if (test_bit(CONSUME_STATE, &ipc_pm->host_sleep_pend))
0135             complete(&ipc_pm->host_sleep_complete);
0136     }
0137 
0138     /* Check for pending HPDA update.
0139      * Pending HP update could be because of sending message was
0140      * put on hold due to Device sleep state or due to TD update
0141      * which could be because of Device Sleep and Host Sleep
0142      * states.
0143      */
0144     if (ipc_pm->pending_hpda_update &&
0145         ipc_pm->host_pm_state == IPC_MEM_HOST_PM_ACTIVE)
0146         ipc_pm_signal_hpda_doorbell(ipc_pm, IPC_HP_PM_TRIGGER, true);
0147 }
0148 
0149 bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active)
0150 {
0151     union ipc_pm_cond old_cond;
0152     union ipc_pm_cond new_cond;
0153     bool link_active;
0154 
0155     /* Save the current D3 state. */
0156     new_cond = ipc_pm->pm_cond;
0157     old_cond = ipc_pm->pm_cond;
0158 
0159     /* Calculate the power state only in the runtime phase. */
0160     switch (unit) {
0161     case IPC_PM_UNIT_IRQ: /* CP irq */
0162         new_cond.irq = active;
0163         break;
0164 
0165     case IPC_PM_UNIT_LINK: /* Device link state. */
0166         new_cond.link = active;
0167         break;
0168 
0169     case IPC_PM_UNIT_HS: /* Host sleep trigger requires Link. */
0170         new_cond.hs = active;
0171         break;
0172 
0173     default:
0174         break;
0175     }
0176 
0177     /* Something changed ? */
0178     if (old_cond.raw == new_cond.raw) {
0179         /* Stay in the current PM state. */
0180         link_active = old_cond.link == IPC_PM_ACTIVE;
0181         goto ret;
0182     }
0183 
0184     ipc_pm->pm_cond = new_cond;
0185 
0186     if (new_cond.link)
0187         ipc_pm_on_link_wake(ipc_pm, unit == IPC_PM_UNIT_LINK);
0188     else if (unit == IPC_PM_UNIT_LINK)
0189         ipc_pm_on_link_sleep(ipc_pm);
0190 
0191     if (old_cond.link == IPC_PM_SLEEP && new_cond.raw) {
0192         link_active = ipc_pm_link_activate(ipc_pm);
0193         goto ret;
0194     }
0195 
0196     link_active = old_cond.link == IPC_PM_ACTIVE;
0197 
0198 ret:
0199     return link_active;
0200 }
0201 
0202 bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm)
0203 {
0204     /* suspend not allowed if host_pm_state is not IPC_MEM_HOST_PM_ACTIVE */
0205     if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE) {
0206         dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d",
0207             ipc_pm->host_pm_state, IPC_MEM_HOST_PM_ACTIVE);
0208         return false;
0209     }
0210 
0211     ipc_pm->host_pm_state = IPC_MEM_HOST_PM_SLEEP_WAIT_D3;
0212 
0213     return true;
0214 }
0215 
0216 bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm)
0217 {
0218     if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_SLEEP) {
0219         dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d",
0220             ipc_pm->host_pm_state, IPC_MEM_HOST_PM_SLEEP);
0221         return false;
0222     }
0223 
0224     /* Sending Sleep Exit message to CP. Update the state */
0225     ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE_WAIT;
0226 
0227     return true;
0228 }
0229 
0230 void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep)
0231 {
0232     if (sleep) {
0233         ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP;
0234         ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP;
0235         ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_SLEEP;
0236     } else {
0237         ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
0238         ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
0239         ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_ACTIVE;
0240         ipc_pm->pm_cond.link = IPC_PM_ACTIVE;
0241     }
0242 }
0243 
0244 bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm, u32 cp_pm_req)
0245 {
0246     if (cp_pm_req == ipc_pm->device_sleep_notification)
0247         return false;
0248 
0249     ipc_pm->device_sleep_notification = cp_pm_req;
0250 
0251     /* Evaluate the PM request. */
0252     switch (ipc_pm->cp_state) {
0253     case IPC_MEM_DEV_PM_ACTIVE:
0254         switch (cp_pm_req) {
0255         case IPC_MEM_DEV_PM_ACTIVE:
0256             break;
0257 
0258         case IPC_MEM_DEV_PM_SLEEP:
0259             /* Inform the PM that the device link can go down. */
0260             ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, false);
0261             return true;
0262 
0263         default:
0264             dev_err(ipc_pm->dev,
0265                 "loc-pm=%d active: confused req-pm=%d",
0266                 ipc_pm->cp_state, cp_pm_req);
0267             break;
0268         }
0269         break;
0270 
0271     case IPC_MEM_DEV_PM_SLEEP:
0272         switch (cp_pm_req) {
0273         case IPC_MEM_DEV_PM_ACTIVE:
0274             /* Inform the PM that the device link is active. */
0275             ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, true);
0276             break;
0277 
0278         case IPC_MEM_DEV_PM_SLEEP:
0279             break;
0280 
0281         default:
0282             dev_err(ipc_pm->dev,
0283                 "loc-pm=%d sleep: confused req-pm=%d",
0284                 ipc_pm->cp_state, cp_pm_req);
0285             break;
0286         }
0287         break;
0288 
0289     default:
0290         dev_err(ipc_pm->dev, "confused loc-pm=%d, req-pm=%d",
0291             ipc_pm->cp_state, cp_pm_req);
0292         break;
0293     }
0294 
0295     return false;
0296 }
0297 
0298 void ipc_pm_init(struct iosm_protocol *ipc_protocol)
0299 {
0300     struct iosm_imem *ipc_imem = ipc_protocol->imem;
0301     struct iosm_pm *ipc_pm = &ipc_protocol->pm;
0302 
0303     ipc_pm->pcie = ipc_imem->pcie;
0304     ipc_pm->dev = ipc_imem->dev;
0305 
0306     ipc_pm->pm_cond.irq = IPC_PM_SLEEP;
0307     ipc_pm->pm_cond.hs = IPC_PM_SLEEP;
0308     ipc_pm->pm_cond.link = IPC_PM_ACTIVE;
0309 
0310     ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
0311     ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
0312     ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
0313 
0314     /* Create generic wait-for-completion handler for Host Sleep
0315      * and device sleep coordination.
0316      */
0317     init_completion(&ipc_pm->host_sleep_complete);
0318 
0319     /* Complete all memory stores before clearing bit */
0320     smp_mb__before_atomic();
0321 
0322     clear_bit(0, &ipc_pm->host_sleep_pend);
0323 
0324     /* Complete all memory stores after clearing bit */
0325     smp_mb__after_atomic();
0326 }
0327 
0328 void ipc_pm_deinit(struct iosm_protocol *proto)
0329 {
0330     struct iosm_pm *ipc_pm = &proto->pm;
0331 
0332     complete(&ipc_pm->host_sleep_complete);
0333 }