mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	Implements state machine to handle host & device sleep. Signed-off-by: M Chetan Kumar <m.chetan.kumar@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			207 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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
 |