1 /*
2 * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <lib/libc/errno.h>
8
9 #include <lib/mmio.h>
10 #include <platform_def.h>
11
12 #include <mtk_mmap_pool.h>
13 #include <notifier/inc/mt_spm_notifier.h>
14 #include <notifier/v4/mt_spm_sspm_intc.h>
15
16 #define MT_SPM_SSPM_MBOX_OFF(x) (SSPM_MBOX_3_BASE + x)
17 #define MT_SPM_MBOX(slot) MT_SPM_SSPM_MBOX_OFF((slot<<2UL))
18
19 /* LOOKUP SSPM_MBOX_SPM_LP1 */
20 #define SSPM_MBOX_SPM_LP_LOOKUP1 MT_SPM_MBOX(0)
21 /* LOOKUP SSPM_MBOX_SPM_LP2 */
22 #define SSPM_MBOX_SPM_LP_LOOKUP2 MT_SPM_MBOX(1)
23 #define SSPM_MBOX_SPM_LP1 MT_SPM_MBOX(2)
24 #define SSPM_MBOX_SPM_LP2 MT_SPM_MBOX(3)
25 #define SSPM_MBOX_SPM_SIZE 16
26 /* 4 mbox is in usage */
27 #define MT_SPM_MBOX_OFFSET(slot) MT_SPM_MBOX((slot + 4))
28
29 enum SSPM_SLEEP_CMD {
30 SLP_TASK_NONE = 0,
31 SLP_TASK_AP_SUSPEND,
32 SLP_TASK_AP_RESUME,
33 SLP_TASK_APSRC_OFF,
34 SLP_TASK_APSRC_ON,
35 SLP_TASK_INFRA_OFF,
36 SLP_TASK_INFRA_ON,
37 SLP_TASK_VCORE_OFF,
38 SLP_TASK_VCORE_ON,
39 SLP_TASK_IDLE_OFF,
40 SLP_TASK_IDLE_ON,
41 SLP_TASK_INFRA_noPERI_OFF,
42 SLP_TASK_INFRA_noPERI_ON,
43 SLP_TASK_ERR = 32,
44 };
45
46 static unsigned int cur_mbox_index;
47
__mt_spm_is_available_index(int cur_idx)48 static int __mt_spm_is_available_index(int cur_idx)
49 {
50 unsigned int val;
51
52 val = mmio_read_32(MT_SPM_MBOX_OFFSET(cur_idx));
53 val = (val >> 30);
54 if (val == 0 || val == 3)
55 return 1;
56 return 0;
57 }
58
__mt_spm_get_available_index(void)59 static int __mt_spm_get_available_index(void)
60 {
61 unsigned int idx = cur_mbox_index;
62 int i = 0;
63
64 for (i = 0 ; i < SSPM_MBOX_SPM_SIZE ; i++) {
65 if (__mt_spm_is_available_index(idx)) {
66 cur_mbox_index = (idx + 1) % SSPM_MBOX_SPM_SIZE;
67 return idx;
68 }
69 idx = (idx + 1) % SSPM_MBOX_SPM_SIZE;
70 }
71 return -EBUSY;
72 }
73
__mt_spm_sspm_write_cmd_queue(int idx,int value)74 static int __mt_spm_sspm_write_cmd_queue(int idx, int value)
75 {
76 unsigned int val;
77
78 val = mmio_read_32(MT_SPM_MBOX_OFFSET(idx));
79 val = val ^ BIT(31);
80 val = (value & 0x3fffffff) | (val & 0xc0000000);
81
82 mmio_write_32(MT_SPM_MBOX_OFFSET(idx), val);
83
84 return 0;
85 }
86
mt_spm_sspm_cmd_enqueue(int cmd)87 void mt_spm_sspm_cmd_enqueue(int cmd)
88 {
89 int idx;
90
91 idx = __mt_spm_get_available_index();
92
93 /* Block when queue full */
94 if (idx == -EBUSY) {
95 while (!__mt_spm_is_available_index(cur_mbox_index))
96 ;
97 idx = cur_mbox_index;
98 cur_mbox_index = (cur_mbox_index+1) % SSPM_MBOX_SPM_SIZE;
99 }
100 __mt_spm_sspm_write_cmd_queue(idx, cmd);
101
102 }
103
mt_spm_sspm_notify_u32(int type,unsigned int val)104 int mt_spm_sspm_notify_u32(int type, unsigned int val)
105 {
106 switch (type) {
107 case MT_SPM_NOTIFY_LP_ENTER:
108 mmio_write_32(SSPM_MBOX_SPM_LP1, val);
109 mt_spm_sspm_cmd_enqueue(SLP_TASK_AP_SUSPEND);
110 DO_SPM_SSPM_LP_NOTIFY();
111 break;
112 case MT_SPM_NOTIFY_LP_LEAVE:
113 mmio_write_32(SSPM_MBOX_SPM_LP1, val);
114 mt_spm_sspm_cmd_enqueue(SLP_TASK_AP_RESUME);
115 DO_SPM_SSPM_LP_NOTIFY();
116 break;
117 case MT_SPM_NOTIFY_IDLE_ENTER:
118 mmio_write_32(SSPM_MBOX_SPM_LP1, val);
119 mt_spm_sspm_cmd_enqueue(SLP_TASK_IDLE_OFF);
120 DO_SPM_SSPM_LP_NOTIFY();
121 break;
122 case MT_SPM_NOTIFY_IDLE_LEAVE:
123 mmio_write_32(SSPM_MBOX_SPM_LP1, val);
124 mt_spm_sspm_cmd_enqueue(SLP_TASK_IDLE_ON);
125 DO_SPM_SSPM_LP_NOTIFY();
126 break;
127 default:
128 break;
129 }
130 return 0;
131 }
132