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 #ifndef IOSM_IPC_PM_H
0007 #define IOSM_IPC_PM_H
0008 
0009 /* Trigger the doorbell interrupt on cp to change the PM sleep/active status */
0010 #define ipc_cp_irq_sleep_control(ipc_pcie, data)                               \
0011     ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_SLEEP, data)
0012 
0013 /* Trigger the doorbell interrupt on CP to do hpda update */
0014 #define ipc_cp_irq_hpda_update(ipc_pcie, data)                                 \
0015     ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_HPDA, 0xFF & (data))
0016 
0017 /**
0018  * union ipc_pm_cond - Conditions for D3 and the sleep message to CP.
0019  * @raw:    raw/combined value for faster check
0020  * @irq:    IRQ towards CP
0021  * @hs:     Host Sleep
0022  * @link:   Device link state.
0023  */
0024 union ipc_pm_cond {
0025     unsigned int raw;
0026 
0027     struct {
0028         unsigned int irq:1,
0029                  hs:1,
0030                  link:1;
0031     };
0032 };
0033 
0034 /**
0035  * enum ipc_mem_host_pm_state - Possible states of the HOST SLEEP finite state
0036  *              machine.
0037  * @IPC_MEM_HOST_PM_ACTIVE:        Host is active
0038  * @IPC_MEM_HOST_PM_ACTIVE_WAIT:       Intermediate state before going to
0039  *                     active
0040  * @IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE:       Intermediate state to wait for idle
0041  *                     before going into sleep
0042  * @IPC_MEM_HOST_PM_SLEEP_WAIT_D3:     Intermediate state to wait for D3
0043  *                     before going to sleep
0044  * @IPC_MEM_HOST_PM_SLEEP:         after this state the interface is not
0045  *                     accessible host is in suspend to RAM
0046  * @IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP: Intermediate state before exiting
0047  *                     sleep
0048  */
0049 enum ipc_mem_host_pm_state {
0050     IPC_MEM_HOST_PM_ACTIVE,
0051     IPC_MEM_HOST_PM_ACTIVE_WAIT,
0052     IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE,
0053     IPC_MEM_HOST_PM_SLEEP_WAIT_D3,
0054     IPC_MEM_HOST_PM_SLEEP,
0055     IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP,
0056 };
0057 
0058 /**
0059  * enum ipc_mem_dev_pm_state - Possible states of the DEVICE SLEEP finite state
0060  *                 machine.
0061  * @IPC_MEM_DEV_PM_ACTIVE:      IPC_MEM_DEV_PM_ACTIVE is the initial
0062  *                  power management state.
0063  *                  IRQ(struct ipc_mem_device_info:
0064  *                  device_sleep_notification)
0065  *                  and DOORBELL-IRQ-HPDA(data) values.
0066  * @IPC_MEM_DEV_PM_SLEEP:       IPC_MEM_DEV_PM_SLEEP is PM state for
0067  *                  sleep.
0068  * @IPC_MEM_DEV_PM_WAKEUP:      DOORBELL-IRQ-DEVICE_WAKE(data).
0069  * @IPC_MEM_DEV_PM_HOST_SLEEP:      DOORBELL-IRQ-HOST_SLEEP(data).
0070  * @IPC_MEM_DEV_PM_ACTIVE_WAIT:     Local intermediate states.
0071  * @IPC_MEM_DEV_PM_FORCE_SLEEP:     DOORBELL-IRQ-FORCE_SLEEP.
0072  * @IPC_MEM_DEV_PM_FORCE_ACTIVE:    DOORBELL-IRQ-FORCE_ACTIVE.
0073  */
0074 enum ipc_mem_dev_pm_state {
0075     IPC_MEM_DEV_PM_ACTIVE,
0076     IPC_MEM_DEV_PM_SLEEP,
0077     IPC_MEM_DEV_PM_WAKEUP,
0078     IPC_MEM_DEV_PM_HOST_SLEEP,
0079     IPC_MEM_DEV_PM_ACTIVE_WAIT,
0080     IPC_MEM_DEV_PM_FORCE_SLEEP = 7,
0081     IPC_MEM_DEV_PM_FORCE_ACTIVE,
0082 };
0083 
0084 /**
0085  * struct iosm_pm - Power management instance
0086  * @pcie:           Pointer to iosm_pcie structure
0087  * @dev:            Pointer to device structure
0088  * @host_pm_state:      PM states for host
0089  * @host_sleep_pend:        Variable to indicate Host Sleep Pending
0090  * @host_sleep_complete:    Generic wait-for-completion used in
0091  *              case of Host Sleep
0092  * @pm_cond:            Conditions for power management
0093  * @ap_state:           Current power management state, the
0094  *              initial state is IPC_MEM_DEV_PM_ACTIVE eq. 0.
0095  * @cp_state:           PM State of CP
0096  * @device_sleep_notification:  last handled device_sleep_notfication
0097  * @pending_hpda_update:    is a HPDA update pending?
0098  */
0099 struct iosm_pm {
0100     struct iosm_pcie *pcie;
0101     struct device *dev;
0102     enum ipc_mem_host_pm_state host_pm_state;
0103     unsigned long host_sleep_pend;
0104     struct completion host_sleep_complete;
0105     union ipc_pm_cond pm_cond;
0106     enum ipc_mem_dev_pm_state ap_state;
0107     enum ipc_mem_dev_pm_state cp_state;
0108     u32 device_sleep_notification;
0109     u8 pending_hpda_update:1;
0110 };
0111 
0112 /**
0113  * enum ipc_pm_unit - Power management units.
0114  * @IPC_PM_UNIT_IRQ:    IRQ towards CP
0115  * @IPC_PM_UNIT_HS: Host Sleep for converged protocol
0116  * @IPC_PM_UNIT_LINK:   Link state controlled by CP.
0117  */
0118 enum ipc_pm_unit {
0119     IPC_PM_UNIT_IRQ,
0120     IPC_PM_UNIT_HS,
0121     IPC_PM_UNIT_LINK,
0122 };
0123 
0124 /**
0125  * ipc_pm_init - Allocate power management component
0126  * @ipc_protocol:   Pointer to iosm_protocol structure
0127  */
0128 void ipc_pm_init(struct iosm_protocol *ipc_protocol);
0129 
0130 /**
0131  * ipc_pm_deinit - Free power management component, invalidating its pointer.
0132  * @ipc_protocol:   Pointer to iosm_protocol structure
0133  */
0134 void ipc_pm_deinit(struct iosm_protocol *ipc_protocol);
0135 
0136 /**
0137  * ipc_pm_dev_slp_notification - Handle a sleep notification message from the
0138  *               device. This can be called from interrupt state
0139  *               This function handles Host Sleep requests too
0140  *               if the Host Sleep protocol is register based.
0141  * @ipc_pm:         Pointer to power management component
0142  * @sleep_notification:     Actual notification from device
0143  *
0144  * Returns: true if dev sleep state has to be checked, false otherwise.
0145  */
0146 bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm,
0147                  u32 sleep_notification);
0148 
0149 /**
0150  * ipc_pm_set_s2idle_sleep - Set PM variables to sleep/active
0151  * @ipc_pm: Pointer to power management component
0152  * @sleep:  true to enter sleep/false to exit sleep
0153  */
0154 void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep);
0155 
0156 /**
0157  * ipc_pm_prepare_host_sleep - Prepare the PM for sleep by entering
0158  *                 IPC_MEM_HOST_PM_SLEEP_WAIT_D3 state.
0159  * @ipc_pm: Pointer to power management component
0160  *
0161  * Returns: true on success, false if the host was not active.
0162  */
0163 bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm);
0164 
0165 /**
0166  * ipc_pm_prepare_host_active - Prepare the PM for wakeup by entering
0167  *              IPC_MEM_HOST_PM_ACTIVE_WAIT state.
0168  * @ipc_pm: Pointer to power management component
0169  *
0170  * Returns: true on success, false if the host was not sleeping.
0171  */
0172 bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm);
0173 
0174 /**
0175  * ipc_pm_wait_for_device_active - Wait upto IPC_PM_ACTIVE_TIMEOUT_MS ms
0176  *                 for the device to reach active state
0177  * @ipc_pm: Pointer to power management component
0178  *
0179  * Returns: true if device is active, false on timeout
0180  */
0181 bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm);
0182 
0183 /**
0184  * ipc_pm_signal_hpda_doorbell - Wake up the device if it is in low power mode
0185  *               and trigger a head pointer update interrupt.
0186  * @ipc_pm:     Pointer to power management component
0187  * @identifier:     specifies what component triggered hpda update irq
0188  * @host_slp_check: if set to true then Host Sleep state machine check will
0189  *          be performed. If Host Sleep state machine allows HP
0190  *          update then only doorbell is triggered otherwise pending
0191  *          flag will be set. If set to false then Host Sleep check
0192  *          will not be performed. This is helpful for Host Sleep
0193  *          negotiation through message ring.
0194  */
0195 void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
0196                  bool host_slp_check);
0197 /**
0198  * ipc_pm_trigger - Update power manager and wake up the link if needed
0199  * @ipc_pm: Pointer to power management component
0200  * @unit:   Power management units
0201  * @active: Device link state
0202  *
0203  * Returns: true if link is unchanged or active, false otherwise
0204  */
0205 bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active);
0206 
0207 #endif