162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Copyright (C) 2020-21 Intel Corporation.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifndef IOSM_IPC_PM_H
762306a36Sopenharmony_ci#define IOSM_IPC_PM_H
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/* Trigger the doorbell interrupt on cp to change the PM sleep/active status */
1062306a36Sopenharmony_ci#define ipc_cp_irq_sleep_control(ipc_pcie, data)                               \
1162306a36Sopenharmony_ci	ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_SLEEP, data)
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* Trigger the doorbell interrupt on CP to do hpda update */
1462306a36Sopenharmony_ci#define ipc_cp_irq_hpda_update(ipc_pcie, data)                                 \
1562306a36Sopenharmony_ci	ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_HPDA, 0xFF & (data))
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/**
1862306a36Sopenharmony_ci * union ipc_pm_cond - Conditions for D3 and the sleep message to CP.
1962306a36Sopenharmony_ci * @raw:	raw/combined value for faster check
2062306a36Sopenharmony_ci * @irq:	IRQ towards CP
2162306a36Sopenharmony_ci * @hs:		Host Sleep
2262306a36Sopenharmony_ci * @link:	Device link state.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ciunion ipc_pm_cond {
2562306a36Sopenharmony_ci	unsigned int raw;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	struct {
2862306a36Sopenharmony_ci		unsigned int irq:1,
2962306a36Sopenharmony_ci			     hs:1,
3062306a36Sopenharmony_ci			     link:1;
3162306a36Sopenharmony_ci	};
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * enum ipc_mem_host_pm_state - Possible states of the HOST SLEEP finite state
3662306a36Sopenharmony_ci *				machine.
3762306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_ACTIVE:		   Host is active
3862306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_ACTIVE_WAIT:	   Intermediate state before going to
3962306a36Sopenharmony_ci *					   active
4062306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE:	   Intermediate state to wait for idle
4162306a36Sopenharmony_ci *					   before going into sleep
4262306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP_WAIT_D3:	   Intermediate state to wait for D3
4362306a36Sopenharmony_ci *					   before going to sleep
4462306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP:		   after this state the interface is not
4562306a36Sopenharmony_ci *					   accessible host is in suspend to RAM
4662306a36Sopenharmony_ci * @IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP: Intermediate state before exiting
4762306a36Sopenharmony_ci *					   sleep
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_cienum ipc_mem_host_pm_state {
5062306a36Sopenharmony_ci	IPC_MEM_HOST_PM_ACTIVE,
5162306a36Sopenharmony_ci	IPC_MEM_HOST_PM_ACTIVE_WAIT,
5262306a36Sopenharmony_ci	IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE,
5362306a36Sopenharmony_ci	IPC_MEM_HOST_PM_SLEEP_WAIT_D3,
5462306a36Sopenharmony_ci	IPC_MEM_HOST_PM_SLEEP,
5562306a36Sopenharmony_ci	IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP,
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * enum ipc_mem_dev_pm_state - Possible states of the DEVICE SLEEP finite state
6062306a36Sopenharmony_ci *			       machine.
6162306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_ACTIVE:		IPC_MEM_DEV_PM_ACTIVE is the initial
6262306a36Sopenharmony_ci *					power management state.
6362306a36Sopenharmony_ci *					IRQ(struct ipc_mem_device_info:
6462306a36Sopenharmony_ci *					device_sleep_notification)
6562306a36Sopenharmony_ci *					and DOORBELL-IRQ-HPDA(data) values.
6662306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_SLEEP:		IPC_MEM_DEV_PM_SLEEP is PM state for
6762306a36Sopenharmony_ci *					sleep.
6862306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_WAKEUP:		DOORBELL-IRQ-DEVICE_WAKE(data).
6962306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_HOST_SLEEP:		DOORBELL-IRQ-HOST_SLEEP(data).
7062306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_ACTIVE_WAIT:		Local intermediate states.
7162306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_FORCE_SLEEP:		DOORBELL-IRQ-FORCE_SLEEP.
7262306a36Sopenharmony_ci * @IPC_MEM_DEV_PM_FORCE_ACTIVE:	DOORBELL-IRQ-FORCE_ACTIVE.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cienum ipc_mem_dev_pm_state {
7562306a36Sopenharmony_ci	IPC_MEM_DEV_PM_ACTIVE,
7662306a36Sopenharmony_ci	IPC_MEM_DEV_PM_SLEEP,
7762306a36Sopenharmony_ci	IPC_MEM_DEV_PM_WAKEUP,
7862306a36Sopenharmony_ci	IPC_MEM_DEV_PM_HOST_SLEEP,
7962306a36Sopenharmony_ci	IPC_MEM_DEV_PM_ACTIVE_WAIT,
8062306a36Sopenharmony_ci	IPC_MEM_DEV_PM_FORCE_SLEEP = 7,
8162306a36Sopenharmony_ci	IPC_MEM_DEV_PM_FORCE_ACTIVE,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci * struct iosm_pm - Power management instance
8662306a36Sopenharmony_ci * @pcie:			Pointer to iosm_pcie structure
8762306a36Sopenharmony_ci * @dev:			Pointer to device structure
8862306a36Sopenharmony_ci * @host_pm_state:		PM states for host
8962306a36Sopenharmony_ci * @host_sleep_pend:		Variable to indicate Host Sleep Pending
9062306a36Sopenharmony_ci * @host_sleep_complete:	Generic wait-for-completion used in
9162306a36Sopenharmony_ci *				case of Host Sleep
9262306a36Sopenharmony_ci * @pm_cond:			Conditions for power management
9362306a36Sopenharmony_ci * @ap_state:			Current power management state, the
9462306a36Sopenharmony_ci *				initial state is IPC_MEM_DEV_PM_ACTIVE eq. 0.
9562306a36Sopenharmony_ci * @cp_state:			PM State of CP
9662306a36Sopenharmony_ci * @device_sleep_notification:	last handled device_sleep_notfication
9762306a36Sopenharmony_ci * @pending_hpda_update:	is a HPDA update pending?
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistruct iosm_pm {
10062306a36Sopenharmony_ci	struct iosm_pcie *pcie;
10162306a36Sopenharmony_ci	struct device *dev;
10262306a36Sopenharmony_ci	enum ipc_mem_host_pm_state host_pm_state;
10362306a36Sopenharmony_ci	unsigned long host_sleep_pend;
10462306a36Sopenharmony_ci	struct completion host_sleep_complete;
10562306a36Sopenharmony_ci	union ipc_pm_cond pm_cond;
10662306a36Sopenharmony_ci	enum ipc_mem_dev_pm_state ap_state;
10762306a36Sopenharmony_ci	enum ipc_mem_dev_pm_state cp_state;
10862306a36Sopenharmony_ci	u32 device_sleep_notification;
10962306a36Sopenharmony_ci	u8 pending_hpda_update:1;
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/**
11362306a36Sopenharmony_ci * enum ipc_pm_unit - Power management units.
11462306a36Sopenharmony_ci * @IPC_PM_UNIT_IRQ:	IRQ towards CP
11562306a36Sopenharmony_ci * @IPC_PM_UNIT_HS:	Host Sleep for converged protocol
11662306a36Sopenharmony_ci * @IPC_PM_UNIT_LINK:	Link state controlled by CP.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cienum ipc_pm_unit {
11962306a36Sopenharmony_ci	IPC_PM_UNIT_IRQ,
12062306a36Sopenharmony_ci	IPC_PM_UNIT_HS,
12162306a36Sopenharmony_ci	IPC_PM_UNIT_LINK,
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/**
12562306a36Sopenharmony_ci * ipc_pm_init - Allocate power management component
12662306a36Sopenharmony_ci * @ipc_protocol:	Pointer to iosm_protocol structure
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_civoid ipc_pm_init(struct iosm_protocol *ipc_protocol);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/**
13162306a36Sopenharmony_ci * ipc_pm_deinit - Free power management component, invalidating its pointer.
13262306a36Sopenharmony_ci * @ipc_protocol:	Pointer to iosm_protocol structure
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_civoid ipc_pm_deinit(struct iosm_protocol *ipc_protocol);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/**
13762306a36Sopenharmony_ci * ipc_pm_dev_slp_notification - Handle a sleep notification message from the
13862306a36Sopenharmony_ci *				 device. This can be called from interrupt state
13962306a36Sopenharmony_ci *				 This function handles Host Sleep requests too
14062306a36Sopenharmony_ci *				 if the Host Sleep protocol is register based.
14162306a36Sopenharmony_ci * @ipc_pm:			Pointer to power management component
14262306a36Sopenharmony_ci * @sleep_notification:		Actual notification from device
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci * Returns: true if dev sleep state has to be checked, false otherwise.
14562306a36Sopenharmony_ci */
14662306a36Sopenharmony_cibool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm,
14762306a36Sopenharmony_ci				 u32 sleep_notification);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/**
15062306a36Sopenharmony_ci * ipc_pm_set_s2idle_sleep - Set PM variables to sleep/active
15162306a36Sopenharmony_ci * @ipc_pm:	Pointer to power management component
15262306a36Sopenharmony_ci * @sleep:	true to enter sleep/false to exit sleep
15362306a36Sopenharmony_ci */
15462306a36Sopenharmony_civoid ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/**
15762306a36Sopenharmony_ci * ipc_pm_prepare_host_sleep - Prepare the PM for sleep by entering
15862306a36Sopenharmony_ci *			       IPC_MEM_HOST_PM_SLEEP_WAIT_D3 state.
15962306a36Sopenharmony_ci * @ipc_pm:	Pointer to power management component
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * Returns: true on success, false if the host was not active.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_cibool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/**
16662306a36Sopenharmony_ci * ipc_pm_prepare_host_active - Prepare the PM for wakeup by entering
16762306a36Sopenharmony_ci *				IPC_MEM_HOST_PM_ACTIVE_WAIT state.
16862306a36Sopenharmony_ci * @ipc_pm:	Pointer to power management component
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * Returns: true on success, false if the host was not sleeping.
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_cibool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * ipc_pm_wait_for_device_active - Wait upto IPC_PM_ACTIVE_TIMEOUT_MS ms
17662306a36Sopenharmony_ci *				   for the device to reach active state
17762306a36Sopenharmony_ci * @ipc_pm:	Pointer to power management component
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * Returns: true if device is active, false on timeout
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cibool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * ipc_pm_signal_hpda_doorbell - Wake up the device if it is in low power mode
18562306a36Sopenharmony_ci *				 and trigger a head pointer update interrupt.
18662306a36Sopenharmony_ci * @ipc_pm:		Pointer to power management component
18762306a36Sopenharmony_ci * @identifier:		specifies what component triggered hpda update irq
18862306a36Sopenharmony_ci * @host_slp_check:	if set to true then Host Sleep state machine check will
18962306a36Sopenharmony_ci *			be performed. If Host Sleep state machine allows HP
19062306a36Sopenharmony_ci *			update then only doorbell is triggered otherwise pending
19162306a36Sopenharmony_ci *			flag will be set. If set to false then Host Sleep check
19262306a36Sopenharmony_ci *			will not be performed. This is helpful for Host Sleep
19362306a36Sopenharmony_ci *			negotiation through message ring.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_civoid ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
19662306a36Sopenharmony_ci				 bool host_slp_check);
19762306a36Sopenharmony_ci/**
19862306a36Sopenharmony_ci * ipc_pm_trigger - Update power manager and wake up the link if needed
19962306a36Sopenharmony_ci * @ipc_pm:	Pointer to power management component
20062306a36Sopenharmony_ci * @unit:	Power management units
20162306a36Sopenharmony_ci * @active:	Device link state
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * Returns: true if link is unchanged or active, false otherwise
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_cibool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci#endif
208