diff --git a/src/drivers/intel/baytrail/ipc.c b/src/drivers/intel/baytrail/ipc.c index 69f1567e8327..a834209357d0 100644 --- a/src/drivers/intel/baytrail/ipc.c +++ b/src/drivers/intel/baytrail/ipc.c @@ -162,7 +162,7 @@ void ipc_platform_do_cmd(struct ipc *ipc) // TODO: signal audio work to enter D3 in normal context /* are we about to enter D3 ? */ - if (iipc->pm_prepare_D3) { + if (iipc->pm_target_state == SOF_PM_STATE_D3) { while (1) { wait_for_interrupt(0); } @@ -235,7 +235,7 @@ int platform_ipc_init(struct ipc *ipc) iipc->dmac = dma_get(dir, caps, dev, DMA_ACCESS_SHARED); /* PM */ - iipc->pm_prepare_D3 = 0; + iipc->pm_target_state = SOF_PM_STATE_D0; /* initial value */ /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, diff --git a/src/drivers/intel/cavs/ipc.c b/src/drivers/intel/cavs/ipc.c index 5ca723f54a98..bb9f15c15db2 100644 --- a/src/drivers/intel/cavs/ipc.c +++ b/src/drivers/intel/cavs/ipc.c @@ -160,7 +160,7 @@ void ipc_platform_do_cmd(struct ipc *ipc) /* are we about to enter D3 ? */ #if CAVS_VERSION < CAVS_VERSION_2_0 - if (iipc->pm_prepare_D3) { + if (iipc->pm_target_state == SOF_PM_STATE_D3) { /* no return - memory will be powered off and IPC sent */ platform_pm_runtime_power_off(); } @@ -178,7 +178,7 @@ void ipc_platform_do_cmd(struct ipc *ipc) ipc_write(IPC_DIPCCTL, ipc_read(IPC_DIPCCTL) | IPC_DIPCCTL_IPCTBIE); #if CAVS_VERSION == CAVS_VERSION_2_0 - if (iipc->pm_prepare_D3) { + if (iipc->pm_target_state == SOF_PM_STATE_D3) { //TODO: add support for Icelake while (1) wait_for_interrupt(5); @@ -246,7 +246,7 @@ int platform_ipc_init(struct ipc *ipc) ipc_process_task, _ipc, 0, 0); /* PM */ - iipc->pm_prepare_D3 = 0; + iipc->pm_target_state = SOF_PM_STATE_D0; /* initial value */ /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, diff --git a/src/drivers/intel/cavs/sue-ipc.c b/src/drivers/intel/cavs/sue-ipc.c index 68d2a649656e..b9163e3bf0c9 100644 --- a/src/drivers/intel/cavs/sue-ipc.c +++ b/src/drivers/intel/cavs/sue-ipc.c @@ -86,7 +86,7 @@ void ipc_platform_do_cmd(struct ipc *ipc) // TODO: signal audio work to enter D3 in normal context /* are we about to enter D3 ? */ - if (iipc->pm_prepare_D3) { + if (iipc->pm_target_state == SOF_PM_STATE_D3) { while (1) wait_for_interrupt(0); } @@ -137,7 +137,7 @@ int platform_ipc_init(struct ipc *ipc) ipc_process_task, _ipc, 0, 0); /* PM */ - iipc->pm_prepare_D3 = 0; + iipc->pm_target_state = SOF_PM_STATE_D0; /* initial value */ return 0; } diff --git a/src/drivers/intel/haswell/ipc.c b/src/drivers/intel/haswell/ipc.c index 6b63c4182a25..7a16ca98ddda 100644 --- a/src/drivers/intel/haswell/ipc.c +++ b/src/drivers/intel/haswell/ipc.c @@ -153,7 +153,7 @@ void ipc_platform_do_cmd(struct ipc *ipc) // TODO: signal audio work to enter D3 in normal context /* are we about to enter D3 ? */ - if (iipc->pm_prepare_D3) { + if (iipc->pm_target_state == SOF_PM_STATE_D3) { while (1) { wait_for_interrupt(0); } @@ -225,7 +225,7 @@ int platform_ipc_init(struct ipc *ipc) iipc->dmac = dma_get(dir, caps, dev, DMA_ACCESS_SHARED); /* PM */ - iipc->pm_prepare_D3 = 0; + iipc->pm_target_state = SOF_PM_STATE_D0; /* initial value */ /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, diff --git a/src/host/ipc.c b/src/host/ipc.c index 8453598bb2fd..0845c2bf1a32 100644 --- a/src/host/ipc.c +++ b/src/host/ipc.c @@ -52,7 +52,7 @@ int platform_ipc_init(struct ipc *ipc) bzero(iipc->page_table, HOST_PAGE_SIZE); /* PM */ - iipc->pm_prepare_D3 = 0; + iipc->pm_target_state = SOF_PM_STATE_D0; /* initial value */ return 0; } diff --git a/src/include/sof/ipc.h b/src/include/sof/ipc.h index a24282b47ed1..e2ed5b8c12f6 100644 --- a/src/include/sof/ipc.h +++ b/src/include/sof/ipc.h @@ -42,6 +42,7 @@ #include #include #include +#include struct sof; struct dai_config; @@ -211,7 +212,7 @@ struct ipc_data { uint8_t *page_table; /* PM */ - int pm_prepare_D3; /* do we need to prepare for D3 */ + uint32_t pm_target_state; /* SOF_PM_STATE_D.. */ }; int ipc_cmd(void); diff --git a/src/include/uapi/abi.h b/src/include/uapi/abi.h index 2bf11c03a6a4..5a08f4039497 100644 --- a/src/include/uapi/abi.h +++ b/src/include/uapi/abi.h @@ -52,7 +52,7 @@ /** \brief SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 6 +#define SOF_ABI_MINOR 7 #define SOF_ABI_PATCH 0 /** \brief SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/src/include/uapi/ipc/header.h b/src/include/uapi/ipc/header.h index 915448c601d4..0b1a8a7f5588 100644 --- a/src/include/uapi/ipc/header.h +++ b/src/include/uapi/ipc/header.h @@ -124,6 +124,8 @@ #define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) #define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) #define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) +#define SOF_IPC_PM_STATE_SET SOF_CMD_TYPE(0x008) +#define SOF_IPC_PM_STATE_GET SOF_CMD_TYPE(0x009) /** \name DSP Command: Component runtime config - multiple different types * @{ diff --git a/src/include/uapi/ipc/pm.h b/src/include/uapi/ipc/pm.h index 5bb7fb4144f0..fb0576811277 100644 --- a/src/include/uapi/ipc/pm.h +++ b/src/include/uapi/ipc/pm.h @@ -75,4 +75,49 @@ struct sof_ipc_pm_core_config { uint32_t enable_mask; } __attribute__((packed)); +/* DSP subsystem power states */ +enum sof_pm_state { + SOF_PM_STATE_D0 = 0, /* D0 only, also initial state */ + SOF_PM_STATE_D3, /* D3 DSP subsystem is power gated*/ + /* internal FW transitions across D0ix substates incl. D0 are allowed */ + SOF_PM_STATE_D0ix, +}; + +/* Flags to allow FW for applying internally clock gating policies */ +enum sof_pm_cg { + SOF_PM_CG_ON = 0, /* Clock gating enabled, */ + SOF_PM_CG_OFF, /* Clock gating disabled */ +}; + +/* Flags to allow FW for applying power gating policies */ +enum sof_pm_pg { + SOF_PM_PG_ON = 0, /* Power gating enabled, */ + SOF_PM_PG_OFF, /* Power gating disabled */ +}; + +/* PM state - SOF_IPC_PM_STATE_SET */ +struct sof_ipc_pm_state { + struct sof_ipc_cmd_hdr hdr; + + uint32_t pm_state; /**< power state SOF_PM_STATE_D.. */ + /**< flag to disable FW logic for autonomous D0ix<->D0 transitions */ + uint32_t prevent_power_gating; + /**< flag to disable FW logic for autonomous clock gating */ + uint32_t prevent_clock_gating; + /**< reserved for future use */ + uint32_t reserved[8]; +} __attribute__((packed)); + +/* PM params info reply - SOF_IPC_PM_STATE_GET */ +struct sof_ipc_pm_state_reply { + struct sof_ipc_reply rhdr; + uint32_t pm_state; /**< power state SOF_PM_STATE_D.. */ + /**< flag to disable FW logic for autonomous D0ix<->D0 transitions */ + uint32_t prevent_power_gating; + /**< flag to disable FW logic for autonomous clock gating */ + uint32_t prevent_clock_gating; + /**< reserved for future use */ + uint32_t reserved[8]; +} __attribute__((packed)); + #endif diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 6dbb1253b79a..c757abcded51 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -647,7 +647,7 @@ static int ipc_pm_context_save(uint32_t header) /* write the context to the host driver */ //mailbox_hostbox_write(0, pm_ctx, sizeof(*pm_ctx)); - iipc->pm_prepare_D3 = 1; + iipc->pm_target_state = SOF_PM_STATE_D3; return 0; } @@ -687,6 +687,47 @@ static int ipc_pm_core_enable(uint32_t header) return 0; } +/* set power management state */ +static int ipc_pm_state_set(uint32_t header) +{ + struct sof_ipc_pm_state pm_state; + struct ipc_data *iipc = ipc_get_drvdata(_ipc); + + /* copy message with ABI safe method */ + IPC_COPY_CMD(pm_state, _ipc->comp_data); + + trace_ipc("ipc: pm state: %d, prevent: cg %d pg %d -> set", + pm_state.pm_state, pm_state.prevent_clock_gating, + pm_state.prevent_power_gating); + + iipc->pm_target_state = pm_state.pm_state; + /* TODO: add handling for clock & power gating policies */ + + return 0; +} + +/* get power management state */ +static int ipc_pm_state_get(uint32_t header) +{ + struct sof_ipc_pm_state_reply reply; + struct ipc_data *iipc = ipc_get_drvdata(_ipc); + + /* write component values to the outbox */ + reply.rhdr.hdr.size = sizeof(reply); + reply.rhdr.hdr.cmd = header; + reply.rhdr.error = 0; + reply.pm_state = iipc->pm_target_state; + reply.prevent_clock_gating = 0; /* TODO: add data handling*/ + reply.prevent_power_gating = 0; /* TODO: add data handling */ + + trace_ipc("ipc: pm state: %d, prevent: cg %d pg %d -> get", + reply.pm_state, reply.prevent_clock_gating, + reply.prevent_power_gating); + + mailbox_hostbox_write(0, &reply, sizeof(reply)); + return 1; +} + static int ipc_glb_pm_message(uint32_t header) { uint32_t cmd = iCS(header); @@ -700,6 +741,10 @@ static int ipc_glb_pm_message(uint32_t header) return ipc_pm_context_size(header); case SOF_IPC_PM_CORE_ENABLE: return ipc_pm_core_enable(header); + case SOF_IPC_PM_STATE_SET: + return ipc_pm_state_set(header); + case SOF_IPC_PM_STATE_GET: + return ipc_pm_state_get(header); case SOF_IPC_PM_CLK_SET: case SOF_IPC_PM_CLK_GET: case SOF_IPC_PM_CLK_REQ: