1*e8e87683SWenzhen Yu /*
2*e8e87683SWenzhen Yu * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3*e8e87683SWenzhen Yu *
4*e8e87683SWenzhen Yu * SPDX-License-Identifier: BSD-3-Clause
5*e8e87683SWenzhen Yu */
6*e8e87683SWenzhen Yu
7*e8e87683SWenzhen Yu #include <errno.h>
8*e8e87683SWenzhen Yu
9*e8e87683SWenzhen Yu #include <common/debug.h>
10*e8e87683SWenzhen Yu #include <lib/mmio.h>
11*e8e87683SWenzhen Yu
12*e8e87683SWenzhen Yu #include <drivers/pmic/pmic_set_lowpower.h>
13*e8e87683SWenzhen Yu #include <drivers/spmi/spmi_common.h>
14*e8e87683SWenzhen Yu #include <lib/mtk_init/mtk_init.h>
15*e8e87683SWenzhen Yu #include <mt_spm_constraint.h>
16*e8e87683SWenzhen Yu #include <mt_spm_pmic_lp.h>
17*e8e87683SWenzhen Yu #include <mt_spm_reg.h>
18*e8e87683SWenzhen Yu
19*e8e87683SWenzhen Yu /* SPMI_M: 6363, SPMI_P: 6373/6316 */
20*e8e87683SWenzhen Yu /* SPMI_M: 6363, SPMI_P: 6373/6316 */
21*e8e87683SWenzhen Yu static struct lp_pmic_cfg {
22*e8e87683SWenzhen Yu uint8_t slave;
23*e8e87683SWenzhen Yu uint8_t master;
24*e8e87683SWenzhen Yu char *name;
25*e8e87683SWenzhen Yu } pmics[] = {
26*e8e87683SWenzhen Yu [LP_MT6363] = {MT6363_SLAVE, SPMI_MASTER_1, "MT6363"},
27*e8e87683SWenzhen Yu [LP_MT6373] = {MT6373_SLAVE, SPMI_MASTER_P_1, "MT6373"},
28*e8e87683SWenzhen Yu [LP_MT6316_1] = {MT6316_S8_SLAVE, SPMI_MASTER_P_1, "MT6316_S8"},
29*e8e87683SWenzhen Yu [LP_MT6316_2] = {MT6316_S6_SLAVE, SPMI_MASTER_P_1, "MT6316_S6"},
30*e8e87683SWenzhen Yu [LP_MT6316_3] = {MT6316_S7_SLAVE, SPMI_MASTER_P_1, "MT6316_S7"},
31*e8e87683SWenzhen Yu [LP_MT6316_4] = {MT6316_S15_SLAVE, SPMI_MASTER_P_1, "MT6316_S15"},
32*e8e87683SWenzhen Yu };
33*e8e87683SWenzhen Yu
34*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP
35*e8e87683SWenzhen Yu static struct pmic_gs_info pmic_gs_dump_info;
36*e8e87683SWenzhen Yu static char *pmic_str[] = {
37*e8e87683SWenzhen Yu [LP_MT6363] = "MT6363",
38*e8e87683SWenzhen Yu [LP_MT6373] = "MT6373",
39*e8e87683SWenzhen Yu [LP_MT6316_1] = "MT6316_1",
40*e8e87683SWenzhen Yu [LP_MT6316_2] = "MT6316_2",
41*e8e87683SWenzhen Yu [LP_MT6316_3] = "MT6316_3",
42*e8e87683SWenzhen Yu [LP_MT6316_4] = "MT6316_4",
43*e8e87683SWenzhen Yu };
44*e8e87683SWenzhen Yu #endif
45*e8e87683SWenzhen Yu struct spmi_device *lp_sdev[LP_PMIC_SLAVE_NUM];
46*e8e87683SWenzhen Yu
47*e8e87683SWenzhen Yu #define VSRAM_CORE_0_35V 56
48*e8e87683SWenzhen Yu #define VSRAM_CORE_0_55V 88
49*e8e87683SWenzhen Yu #define VSRAM_CORE_0_75V 120
50*e8e87683SWenzhen Yu
51*e8e87683SWenzhen Yu /* VSRAM_CORE Low bound */
52*e8e87683SWenzhen Yu #ifdef MTK_AGING_FLAVOR_LOAD
53*e8e87683SWenzhen Yu #define SUSPEND_AGING_VAL_SHIFT 3
54*e8e87683SWenzhen Yu #define SUSPEND_AGING_VAL_DEFAULT 85
55*e8e87683SWenzhen Yu #define VSRAM_CORE_LOWBOUND (74 - SUSPEND_AGING_VAL_SHIFT)
56*e8e87683SWenzhen Yu #else
57*e8e87683SWenzhen Yu #define VSRAM_CORE_LOWBOUND 74
58*e8e87683SWenzhen Yu #endif
59*e8e87683SWenzhen Yu #define MT6363_LP_REG 0x1687
60*e8e87683SWenzhen Yu #define MT6363_VIO18_SWITCH 0x53
61*e8e87683SWenzhen Yu #define MT6373_VIO18_SWITCH 0x58
62*e8e87683SWenzhen Yu
63*e8e87683SWenzhen Yu static uint32_t vcore_sram_suspend_vol = VSRAM_CORE_0_55V;
64*e8e87683SWenzhen Yu static bool vcore_sram_lp_enable = true;
65*e8e87683SWenzhen Yu static bool vcore_lp_enable = true;
66*e8e87683SWenzhen Yu
get_vcore_sram_suspend_vol(void)67*e8e87683SWenzhen Yu static uint32_t get_vcore_sram_suspend_vol(void)
68*e8e87683SWenzhen Yu {
69*e8e87683SWenzhen Yu uint8_t value;
70*e8e87683SWenzhen Yu /* Set vcore_sram to 0.55V by default */
71*e8e87683SWenzhen Yu value = VSRAM_CORE_0_55V;
72*e8e87683SWenzhen Yu
73*e8e87683SWenzhen Yu #ifdef MTK_AGING_FLAVOR_LOAD
74*e8e87683SWenzhen Yu value -= SUSPEND_AGING_VAL_SHIFT;
75*e8e87683SWenzhen Yu if (value > SUSPEND_AGING_VAL_DEFAULT)
76*e8e87683SWenzhen Yu value = SUSPEND_AGING_VAL_DEFAULT;
77*e8e87683SWenzhen Yu INFO("%s(%d) enable aging with value: %u\n",
78*e8e87683SWenzhen Yu __func__, __LINE__, value);
79*e8e87683SWenzhen Yu #endif
80*e8e87683SWenzhen Yu return value;
81*e8e87683SWenzhen Yu }
82*e8e87683SWenzhen Yu
83*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP
mt_spm_dump_pmic_gs(uint32_t cmd)84*e8e87683SWenzhen Yu static void mt_spm_dump_pmic_gs(uint32_t cmd)
85*e8e87683SWenzhen Yu {
86*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP_SUSPEND
87*e8e87683SWenzhen Yu if (cmd & MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND) { /* Suspend enter */
88*e8e87683SWenzhen Yu mt_spm_pmic_gs_dump(SUSPEND, LP_MT6363);
89*e8e87683SWenzhen Yu mt_spm_pmic_gs_dump(SUSPEND, LP_MT6373);
90*e8e87683SWenzhen Yu }
91*e8e87683SWenzhen Yu #endif
92*e8e87683SWenzhen Yu if (cmd & MT_RM_CONSTRAINT_ALLOW_VCORE_LP) {
93*e8e87683SWenzhen Yu if (cmd & MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF) { /* SODI3 */
94*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP_SODI3
95*e8e87683SWenzhen Yu mt_spm_pmic_gs_dump(SODI3, LP_MT6363);
96*e8e87683SWenzhen Yu mt_spm_pmic_gs_dump(SODI3, LP_MT6373);
97*e8e87683SWenzhen Yu #endif
98*e8e87683SWenzhen Yu } else { /* DPIDLE enter */
99*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP_DPIDLE
100*e8e87683SWenzhen Yu mt_spm_pmic_gs_dump(DPIDLE, LP_MT6363);
101*e8e87683SWenzhen Yu mt_spm_pmic_gs_dump(DPIDLE, LP_MT6373);
102*e8e87683SWenzhen Yu #endif
103*e8e87683SWenzhen Yu }
104*e8e87683SWenzhen Yu }
105*e8e87683SWenzhen Yu }
106*e8e87683SWenzhen Yu #endif
107*e8e87683SWenzhen Yu
spm_lp_setting_init(void)108*e8e87683SWenzhen Yu int spm_lp_setting_init(void)
109*e8e87683SWenzhen Yu {
110*e8e87683SWenzhen Yu uint8_t i, slvid, spmi_master;
111*e8e87683SWenzhen Yu
112*e8e87683SWenzhen Yu for (i = 0; i < ARRAY_SIZE(pmics); i++) {
113*e8e87683SWenzhen Yu slvid = pmics[i].slave;
114*e8e87683SWenzhen Yu spmi_master = pmics[i].master;
115*e8e87683SWenzhen Yu lp_sdev[i] = get_spmi_device(spmi_master, slvid);
116*e8e87683SWenzhen Yu if (!lp_sdev[i])
117*e8e87683SWenzhen Yu return -ENODEV;
118*e8e87683SWenzhen Yu }
119*e8e87683SWenzhen Yu
120*e8e87683SWenzhen Yu PMIC_SLVID_BUCK_SET_LP(MT6316, S8, VBUCK1, RC8,
121*e8e87683SWenzhen Yu false, OP_MODE_LP, HW_OFF);
122*e8e87683SWenzhen Yu
123*e8e87683SWenzhen Yu /* Get suspend case vcore_sram sleep voltage */
124*e8e87683SWenzhen Yu vcore_sram_suspend_vol = get_vcore_sram_suspend_vol();
125*e8e87683SWenzhen Yu
126*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP
127*e8e87683SWenzhen Yu pmic_gs_dump_info.lp_sdev = lp_sdev;
128*e8e87683SWenzhen Yu pmic_gs_dump_info.pmic_str = pmic_str;
129*e8e87683SWenzhen Yu pmic_gs_dump_info.pmic_num = LP_PMIC_SLAVE_NUM;
130*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP_SUSPEND
131*e8e87683SWenzhen Yu pmic_gs_dump_info.scen_gs[SUSPEND].data = pmic_gs_suspend;
132*e8e87683SWenzhen Yu #endif
133*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP_SODI3
134*e8e87683SWenzhen Yu pmic_gs_dump_info.scen_gs[SODI3].data = pmic_gs_sodi3;
135*e8e87683SWenzhen Yu #endif
136*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_GS_DUMP_DPIDLE
137*e8e87683SWenzhen Yu pmic_gs_dump_info.scen_gs[DPIDLE].data = pmic_gs_dpidle;
138*e8e87683SWenzhen Yu #endif
139*e8e87683SWenzhen Yu return register_pmic_gs_info(&pmic_gs_dump_info);
140*e8e87683SWenzhen Yu #else
141*e8e87683SWenzhen Yu return 0;
142*e8e87683SWenzhen Yu #endif
143*e8e87683SWenzhen Yu }
144*e8e87683SWenzhen Yu
145*e8e87683SWenzhen Yu #ifdef MTK_SPM_PMIC_LP_SUPPORT
146*e8e87683SWenzhen Yu MTK_PLAT_SETUP_0_INIT(spm_lp_setting_init);
147*e8e87683SWenzhen Yu #endif
148*e8e87683SWenzhen Yu
set_vcore_lp_enable(bool enable)149*e8e87683SWenzhen Yu void set_vcore_lp_enable(bool enable)
150*e8e87683SWenzhen Yu {
151*e8e87683SWenzhen Yu vcore_lp_enable = enable;
152*e8e87683SWenzhen Yu }
153*e8e87683SWenzhen Yu
get_vcore_lp_enable(void)154*e8e87683SWenzhen Yu bool get_vcore_lp_enable(void)
155*e8e87683SWenzhen Yu {
156*e8e87683SWenzhen Yu return vcore_lp_enable;
157*e8e87683SWenzhen Yu }
158*e8e87683SWenzhen Yu
set_vsram_lp_enable(bool enable)159*e8e87683SWenzhen Yu void set_vsram_lp_enable(bool enable)
160*e8e87683SWenzhen Yu {
161*e8e87683SWenzhen Yu vcore_sram_lp_enable = enable;
162*e8e87683SWenzhen Yu }
163*e8e87683SWenzhen Yu
get_vsram_lp_enable(void)164*e8e87683SWenzhen Yu bool get_vsram_lp_enable(void)
165*e8e87683SWenzhen Yu {
166*e8e87683SWenzhen Yu return vcore_sram_lp_enable;
167*e8e87683SWenzhen Yu }
168*e8e87683SWenzhen Yu
set_vsram_lp_volt(uint32_t volt)169*e8e87683SWenzhen Yu void set_vsram_lp_volt(uint32_t volt)
170*e8e87683SWenzhen Yu {
171*e8e87683SWenzhen Yu /* Allow 0.35V ~ 0.75V */
172*e8e87683SWenzhen Yu if (volt < VSRAM_CORE_0_35V || volt > VSRAM_CORE_0_75V)
173*e8e87683SWenzhen Yu return;
174*e8e87683SWenzhen Yu vcore_sram_suspend_vol = volt;
175*e8e87683SWenzhen Yu }
176*e8e87683SWenzhen Yu
get_vsram_lp_volt(void)177*e8e87683SWenzhen Yu uint32_t get_vsram_lp_volt(void)
178*e8e87683SWenzhen Yu {
179*e8e87683SWenzhen Yu return vcore_sram_suspend_vol;
180*e8e87683SWenzhen Yu }
181*e8e87683SWenzhen Yu
pmic_lp_setting(uint8_t data)182*e8e87683SWenzhen Yu static int pmic_lp_setting(uint8_t data)
183*e8e87683SWenzhen Yu {
184*e8e87683SWenzhen Yu int ret;
185*e8e87683SWenzhen Yu
186*e8e87683SWenzhen Yu if (data != 0x0 && data != 0x1)
187*e8e87683SWenzhen Yu return -ENODEV;
188*e8e87683SWenzhen Yu /* SUSPEND:VS1 HW2&RC9 normal mode */
189*e8e87683SWenzhen Yu PMIC_BUCK_SET_LP(MT6363, VS1, HW2,
190*e8e87683SWenzhen Yu false, OP_MODE_LP, HW_LP);
191*e8e87683SWenzhen Yu PMIC_BUCK_SET_LP(MT6363, VS1, RC9,
192*e8e87683SWenzhen Yu false, OP_MODE_MU, HW_ON);
193*e8e87683SWenzhen Yu PMIC_LDO_SET_LP(MT6363, VIO18, HW2,
194*e8e87683SWenzhen Yu false, OP_MODE_LP, HW_LP);
195*e8e87683SWenzhen Yu PMIC_LDO_SET_LP(MT6363, VIO18, RC9,
196*e8e87683SWenzhen Yu false, OP_MODE_MU, HW_ON);
197*e8e87683SWenzhen Yu
198*e8e87683SWenzhen Yu /* Switch DIG18 to VIO18 for power saving */
199*e8e87683SWenzhen Yu ret = spmi_ext_register_writel(lp_sdev[LP_MT6363], MT6363_VIO18_SWITCH, &data, 1);
200*e8e87683SWenzhen Yu if (ret)
201*e8e87683SWenzhen Yu INFO("MT6363 RG_VIO18 spmi failed\n");
202*e8e87683SWenzhen Yu
203*e8e87683SWenzhen Yu ret = spmi_ext_register_writel(lp_sdev[LP_MT6373], MT6373_VIO18_SWITCH, &data, 1);
204*e8e87683SWenzhen Yu if (ret)
205*e8e87683SWenzhen Yu INFO("MT6373 RG_VIO18 spmi failed\n");
206*e8e87683SWenzhen Yu return ret;
207*e8e87683SWenzhen Yu }
208*e8e87683SWenzhen Yu
do_spm_low_power(enum SPM_PWR_TYPE type,uint32_t cmd)209*e8e87683SWenzhen Yu int do_spm_low_power(enum SPM_PWR_TYPE type, uint32_t cmd)
210*e8e87683SWenzhen Yu {
211*e8e87683SWenzhen Yu int ret;
212*e8e87683SWenzhen Yu uint8_t value;
213*e8e87683SWenzhen Yu bool enter_suspend, vcore_sram_lp = false;
214*e8e87683SWenzhen Yu
215*e8e87683SWenzhen Yu if (type == SPM_LP_ENTER) {
216*e8e87683SWenzhen Yu enter_suspend = true;
217*e8e87683SWenzhen Yu vcore_sram_lp = vcore_sram_lp_enable;
218*e8e87683SWenzhen Yu
219*e8e87683SWenzhen Yu if (cmd & MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND) {
220*e8e87683SWenzhen Yu value = vcore_sram_suspend_vol;
221*e8e87683SWenzhen Yu if (value < VSRAM_CORE_LOWBOUND ||
222*e8e87683SWenzhen Yu value > VSRAM_CORE_0_75V) {
223*e8e87683SWenzhen Yu INFO("Vsram_core voltage wrong\n");
224*e8e87683SWenzhen Yu panic();
225*e8e87683SWenzhen Yu }
226*e8e87683SWenzhen Yu } else {
227*e8e87683SWenzhen Yu value = VSRAM_CORE_0_55V;
228*e8e87683SWenzhen Yu }
229*e8e87683SWenzhen Yu } else {
230*e8e87683SWenzhen Yu enter_suspend = false;
231*e8e87683SWenzhen Yu vcore_sram_lp = false;
232*e8e87683SWenzhen Yu value = VSRAM_CORE_0_75V;
233*e8e87683SWenzhen Yu }
234*e8e87683SWenzhen Yu /* Enable VA12_2/VSRAM_CPUL HW_LP for suspend/idle */
235*e8e87683SWenzhen Yu PMIC_LDO_SET_LP(MT6363, VA12_2, HW2, enter_suspend, OP_MODE_LP, HW_LP);
236*e8e87683SWenzhen Yu PMIC_LDO_SET_LP(MT6363, VSRAM_CPUL, HW2,
237*e8e87683SWenzhen Yu enter_suspend, OP_MODE_LP, HW_LP);
238*e8e87683SWenzhen Yu
239*e8e87683SWenzhen Yu if (!(cmd & MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND))
240*e8e87683SWenzhen Yu return 0;
241*e8e87683SWenzhen Yu PMIC_SLVID_BUCK_SET_LP(MT6316, S8, VBUCK1, HW2, vcore_lp_enable,
242*e8e87683SWenzhen Yu OP_MODE_LP, HW_LP);
243*e8e87683SWenzhen Yu PMIC_BUCK_SET_LP(MT6363, VBUCK4, HW0, vcore_sram_lp,
244*e8e87683SWenzhen Yu OP_MODE_LP, HW_LP);
245*e8e87683SWenzhen Yu PMIC_BUCK_SET_LP(MT6363, VBUCK4, HW2, !enter_suspend,
246*e8e87683SWenzhen Yu OP_MODE_LP, HW_LP);
247*e8e87683SWenzhen Yu ret = spmi_ext_register_writel(lp_sdev[LP_MT6363], MT6363_LP_REG, &value, 1);
248*e8e87683SWenzhen Yu if (ret)
249*e8e87683SWenzhen Yu INFO("BUCK(VSRAM_CORE) spmi write failed\n");
250*e8e87683SWenzhen Yu
251*e8e87683SWenzhen Yu if (cmd & MT_RM_CONSTRAINT_ALLOW_AP_PLAT_SUSPEND)
252*e8e87683SWenzhen Yu pmic_lp_setting(enter_suspend ? 1 : 0);
253*e8e87683SWenzhen Yu
254*e8e87683SWenzhen Yu return 0;
255*e8e87683SWenzhen Yu }
256