1313#include "registers.h"
1414
1515#define AVS_IPC_TIMEOUT_MS 300
16+ #define AVS_D0IX_DELAY_MS 300
17+
18+ static int
19+ avs_dsp_set_d0ix (struct avs_dev * adev , bool enable )
20+ {
21+ struct avs_ipc * ipc = adev -> ipc ;
22+ int ret ;
23+
24+ /* Is transition required? */
25+ if (ipc -> in_d0ix == enable )
26+ return 0 ;
27+
28+ ret = avs_dsp_op (adev , set_d0ix , enable );
29+ if (ret ) {
30+ /* Prevent further d0ix attempts on conscious IPC failure. */
31+ if (ret == - AVS_EIPC )
32+ atomic_inc (& ipc -> d0ix_disable_depth );
33+
34+ ipc -> in_d0ix = false;
35+ return ret ;
36+ }
37+
38+ ipc -> in_d0ix = enable ;
39+ return 0 ;
40+ }
41+
42+ static void avs_dsp_schedule_d0ix (struct avs_dev * adev , struct avs_ipc_msg * tx )
43+ {
44+ if (atomic_read (& adev -> ipc -> d0ix_disable_depth ))
45+ return ;
46+
47+ mod_delayed_work (system_power_efficient_wq , & adev -> ipc -> d0ix_work ,
48+ msecs_to_jiffies (AVS_D0IX_DELAY_MS ));
49+ }
50+
51+ static void avs_dsp_d0ix_work (struct work_struct * work )
52+ {
53+ struct avs_ipc * ipc = container_of (work , struct avs_ipc , d0ix_work .work );
54+
55+ avs_dsp_set_d0ix (to_avs_dev (ipc -> dev ), true);
56+ }
57+
58+ static int avs_dsp_wake_d0i0 (struct avs_dev * adev , struct avs_ipc_msg * tx )
59+ {
60+ struct avs_ipc * ipc = adev -> ipc ;
61+
62+ if (!atomic_read (& ipc -> d0ix_disable_depth )) {
63+ cancel_delayed_work_sync (& ipc -> d0ix_work );
64+ return avs_dsp_set_d0ix (adev , false);
65+ }
66+
67+ return 0 ;
68+ }
69+
70+ int avs_dsp_disable_d0ix (struct avs_dev * adev )
71+ {
72+ struct avs_ipc * ipc = adev -> ipc ;
73+
74+ /* Prevent PG only on the first disable. */
75+ if (atomic_add_return (1 , & ipc -> d0ix_disable_depth ) == 1 ) {
76+ cancel_delayed_work_sync (& ipc -> d0ix_work );
77+ return avs_dsp_set_d0ix (adev , false);
78+ }
79+
80+ return 0 ;
81+ }
82+
83+ int avs_dsp_enable_d0ix (struct avs_dev * adev )
84+ {
85+ struct avs_ipc * ipc = adev -> ipc ;
86+
87+ if (atomic_dec_and_test (& ipc -> d0ix_disable_depth ))
88+ queue_delayed_work (system_power_efficient_wq , & ipc -> d0ix_work ,
89+ msecs_to_jiffies (AVS_D0IX_DELAY_MS ));
90+ return 0 ;
91+ }
1692
1793static void avs_dsp_recovery (struct avs_dev * adev )
1894{
@@ -88,6 +164,8 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
88164
89165 dev_crit (adev -> dev , "communication severed, rebooting dsp..\n" );
90166
167+ cancel_delayed_work_sync (& ipc -> d0ix_work );
168+ ipc -> in_d0ix = false;
91169 /* Re-enabled on recovery completion. */
92170 pm_runtime_disable (adev -> dev );
93171
@@ -393,10 +471,35 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
393471 return ret ;
394472}
395473
474+ static int avs_dsp_send_msg_sequence (struct avs_dev * adev , struct avs_ipc_msg * request ,
475+ struct avs_ipc_msg * reply , int timeout , bool wake_d0i0 ,
476+ bool schedule_d0ix )
477+ {
478+ int ret ;
479+
480+ if (wake_d0i0 ) {
481+ ret = avs_dsp_wake_d0i0 (adev , request );
482+ if (ret )
483+ return ret ;
484+ }
485+
486+ ret = avs_dsp_do_send_msg (adev , request , reply , timeout );
487+ if (ret )
488+ return ret ;
489+
490+ if (schedule_d0ix )
491+ avs_dsp_schedule_d0ix (adev , request );
492+
493+ return 0 ;
494+ }
495+
396496int avs_dsp_send_msg_timeout (struct avs_dev * adev , struct avs_ipc_msg * request ,
397497 struct avs_ipc_msg * reply , int timeout )
398498{
399- return avs_dsp_do_send_msg (adev , request , reply , timeout );
499+ bool wake_d0i0 = avs_dsp_op (adev , d0ix_toggle , request , true);
500+ bool schedule_d0ix = avs_dsp_op (adev , d0ix_toggle , request , false);
501+
502+ return avs_dsp_send_msg_sequence (adev , request , reply , timeout , wake_d0i0 , schedule_d0ix );
400503}
401504
402505int avs_dsp_send_msg (struct avs_dev * adev , struct avs_ipc_msg * request ,
@@ -405,6 +508,19 @@ int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
405508 return avs_dsp_send_msg_timeout (adev , request , reply , adev -> ipc -> default_timeout_ms );
406509}
407510
511+ int avs_dsp_send_pm_msg_timeout (struct avs_dev * adev , struct avs_ipc_msg * request ,
512+ struct avs_ipc_msg * reply , int timeout , bool wake_d0i0 )
513+ {
514+ return avs_dsp_send_msg_sequence (adev , request , reply , timeout , wake_d0i0 , false);
515+ }
516+
517+ int avs_dsp_send_pm_msg (struct avs_dev * adev , struct avs_ipc_msg * request ,
518+ struct avs_ipc_msg * reply , bool wake_d0i0 )
519+ {
520+ return avs_dsp_send_pm_msg_timeout (adev , request , reply , adev -> ipc -> default_timeout_ms ,
521+ wake_d0i0 );
522+ }
523+
408524static int avs_dsp_do_send_rom_msg (struct avs_dev * adev , struct avs_ipc_msg * request , int timeout )
409525{
410526 struct avs_ipc * ipc = adev -> ipc ;
@@ -465,6 +581,7 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
465581 ipc -> ready = false;
466582 ipc -> default_timeout_ms = AVS_IPC_TIMEOUT_MS ;
467583 INIT_WORK (& ipc -> recovery_work , avs_dsp_recovery_work );
584+ INIT_DELAYED_WORK (& ipc -> d0ix_work , avs_dsp_d0ix_work );
468585 init_completion (& ipc -> done_completion );
469586 init_completion (& ipc -> busy_completion );
470587 spin_lock_init (& ipc -> rx_lock );
@@ -477,4 +594,6 @@ void avs_ipc_block(struct avs_ipc *ipc)
477594{
478595 ipc -> ready = false;
479596 cancel_work_sync (& ipc -> recovery_work );
597+ cancel_delayed_work_sync (& ipc -> d0ix_work );
598+ ipc -> in_d0ix = false;
480599}
0 commit comments