xref: /rk3399_ARM-atf/plat/mediatek/drivers/spm/mt8189/mt_spm_idle.c (revision af0370f25a6663a0d737bbfb3985df4232eaaa55)
1 /*
2  * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <common/debug.h>
12 #include <lib/mmio.h>
13 
14 #include <drivers/spm/mt_spm_resource_req.h>
15 #include <lib/pm/mtk_pm.h>
16 #include <lpm_v2/mt_lp_api.h>
17 #include <mt_spm.h>
18 #include <mt_spm_conservation.h>
19 #include <mt_spm_idle.h>
20 #include <mt_spm_internal.h>
21 #include <mt_spm_reg.h>
22 #include <mt_spm_stats.h>
23 
24 #define SPM_BYPASS_SYSPWREQ_GENERIC 1
25 
26 /* Default will be the bus26m or deeper spm's low power mode*/
27 #define __WAKE_SRC_FOR_IDLE_COMMON__                                           \
28 	((R12_PCM_TIMER_B) | (R12_KP_IRQ_B) | (R12_CONN2AP_WAKEUP_B) |         \
29 	 (R12_EINT_EVENT_B) | (R12_CONN_WDT_IRQ_B) | (R12_SSPM2SPM_WAKEUP_B) | \
30 	 (R12_SCP2SPM_WAKEUP_B) | (R12_VADSP2SPM_WAKEUP_B) |                   \
31 	 (R12_USB0_CDSC_B) | (R12_USB0_POWERDWN_B) | (R12_SBD_INTR_B) |        \
32 	 (R12_UART2SPM_IRQ_B) | (R12_SYS_TIMER_EVENT_B) |                      \
33 	 (R12_EINT_EVENT_SECURE_B) | (R12_AFE_IRQ_MCU_B) |                     \
34 	 (R12_SYS_CIRQ_IRQ_B) | (R12_AP2AP_PEER_WAKEUP_B) | (R12_CPU_WAKEUP) | \
35 	 (R12_APUSYS_WAKE_HOST_B) | (R12_PCIE_MAC_IRQ_WAKE_B) |                \
36 	 (R12_MSDC_WAKEUP_EVENT_B))
37 
38 #if defined(CFG_MICROTRUST_TEE_SUPPORT)
39 #define WAKE_SRC_FOR_IDLE (__WAKE_SRC_FOR_IDLE_COMMON__)
40 #else
41 #define WAKE_SRC_FOR_IDLE (__WAKE_SRC_FOR_IDLE_COMMON__ | R12_SEJ_B)
42 #endif
43 
44 static struct pwr_ctrl idle_spm_pwr = {
45 	.wake_src = WAKE_SRC_FOR_IDLE,
46 
47 	/* Auto-gen Start */
48 
49 	/* SPM_SRC_REQ */
50 	.reg_spm_adsp_mailbox_req = 0,
51 	.reg_spm_apsrc_req = 0,
52 	.reg_spm_ddren_req = 0,
53 	.reg_spm_dvfs_req = 0,
54 	.reg_spm_emi_req = 0,
55 	.reg_spm_f26m_req = 0,
56 	.reg_spm_infra_req = 0,
57 	.reg_spm_pmic_req = 0,
58 	.reg_spm_scp_mailbox_req = 0,
59 	.reg_spm_sspm_mailbox_req = 0,
60 	.reg_spm_sw_mailbox_req = 0,
61 	.reg_spm_vcore_req = 0,
62 	.reg_spm_vrf18_req = 0,
63 	.adsp_mailbox_state = 0,
64 	.apsrc_state = 0,
65 	.ddren_state = 0,
66 	.dvfs_state = 0,
67 	.emi_state = 0,
68 	.f26m_state = 0,
69 	.infra_state = 0,
70 	.pmic_state = 0,
71 	.scp_mailbox_state = 0,
72 	.sspm_mailbox_state = 0,
73 	.sw_mailbox_state = 0,
74 	.vcore_state = 0,
75 	.vrf18_state = 0,
76 
77 	/* SPM_SRC_MASK_0 */
78 	.reg_apu_apsrc_req_mask_b = 0x1,
79 	.reg_apu_ddren_req_mask_b = 0x1,
80 	.reg_apu_emi_req_mask_b = 0x1,
81 	.reg_apu_infra_req_mask_b = 0x1,
82 	.reg_apu_pmic_req_mask_b = 0x1,
83 	.reg_apu_srcclkena_mask_b = 0x1,
84 	.reg_apu_vrf18_req_mask_b = 0x1,
85 	.reg_audio_dsp_apsrc_req_mask_b = 0x0,
86 	.reg_audio_dsp_ddren_req_mask_b = 0x0,
87 	.reg_audio_dsp_emi_req_mask_b = 0x0,
88 	.reg_audio_dsp_infra_req_mask_b = 0x0,
89 	.reg_audio_dsp_pmic_req_mask_b = 0x0,
90 	.reg_audio_dsp_srcclkena_mask_b = 0x0,
91 	.reg_audio_dsp_vcore_req_mask_b = 0x0,
92 	.reg_audio_dsp_vrf18_req_mask_b = 0x0,
93 	.reg_cam_apsrc_req_mask_b = 0x1,
94 	.reg_cam_ddren_req_mask_b = 0x1,
95 	.reg_cam_emi_req_mask_b = 0x1,
96 	.reg_cam_infra_req_mask_b = 0x0,
97 	.reg_cam_pmic_req_mask_b = 0x0,
98 	.reg_cam_srcclkena_mask_b = 0x0,
99 	.reg_cam_vrf18_req_mask_b = 0x0,
100 	.reg_mdp_emi_req_mask_b = 0x1,
101 
102 	/* SPM_SRC_MASK_1 */
103 	.reg_ccif_apsrc_req_mask_b = 0x0,
104 	.reg_ccif_emi_req_mask_b = 0xfff,
105 
106 	/* SPM_SRC_MASK_2 */
107 	.reg_ccif_infra_req_mask_b = 0x0,
108 	.reg_ccif_pmic_req_mask_b = 0xfff,
109 
110 	/* SPM_SRC_MASK_3 */
111 	.reg_ccif_srcclkena_mask_b = 0x0,
112 	.reg_ccif_vrf18_req_mask_b = 0xfff,
113 	.reg_ccu_apsrc_req_mask_b = 0x0,
114 	.reg_ccu_ddren_req_mask_b = 0x0,
115 	.reg_ccu_emi_req_mask_b = 0x0,
116 	.reg_ccu_infra_req_mask_b = 0x0,
117 	.reg_ccu_pmic_req_mask_b = 0x0,
118 	.reg_ccu_srcclkena_mask_b = 0x0,
119 	.reg_ccu_vrf18_req_mask_b = 0x0,
120 	.reg_cg_check_apsrc_req_mask_b = 0x1,
121 
122 	/* SPM_SRC_MASK_4 */
123 	.reg_cg_check_ddren_req_mask_b = 0x1,
124 	.reg_cg_check_emi_req_mask_b = 0x1,
125 	.reg_cg_check_infra_req_mask_b = 0x1,
126 	.reg_cg_check_pmic_req_mask_b = 0x1,
127 	.reg_cg_check_srcclkena_mask_b = 0x1,
128 	.reg_cg_check_vcore_req_mask_b = 0x1,
129 	.reg_cg_check_vrf18_req_mask_b = 0x1,
130 	.reg_conn_apsrc_req_mask_b = 0x1,
131 	.reg_conn_ddren_req_mask_b = 0x1,
132 	.reg_conn_emi_req_mask_b = 0x1,
133 	.reg_conn_infra_req_mask_b = 0x1,
134 	.reg_conn_pmic_req_mask_b = 0x1,
135 	.reg_conn_srcclkena_mask_b = 0x1,
136 	.reg_conn_srcclkenb_mask_b = 0x1,
137 	.reg_conn_vcore_req_mask_b = 0x1,
138 	.reg_conn_vrf18_req_mask_b = 0x1,
139 	.reg_cpueb_apsrc_req_mask_b = 0x1,
140 	.reg_cpueb_ddren_req_mask_b = 0x1,
141 	.reg_cpueb_emi_req_mask_b = 0x1,
142 	.reg_cpueb_infra_req_mask_b = 0x1,
143 	.reg_cpueb_pmic_req_mask_b = 0x1,
144 	.reg_cpueb_srcclkena_mask_b = 0x1,
145 	.reg_cpueb_vrf18_req_mask_b = 0x1,
146 	.reg_disp0_apsrc_req_mask_b = 0x1,
147 	.reg_disp0_ddren_req_mask_b = 0x1,
148 	.reg_disp0_emi_req_mask_b = 0x1,
149 	.reg_disp0_infra_req_mask_b = 0x1,
150 	.reg_disp0_pmic_req_mask_b = 0x0,
151 	.reg_disp0_srcclkena_mask_b = 0x0,
152 	.reg_disp0_vrf18_req_mask_b = 0x1,
153 	.reg_disp1_apsrc_req_mask_b = 0x0,
154 	.reg_disp1_ddren_req_mask_b = 0x0,
155 
156 	/* SPM_SRC_MASK_5 */
157 	.reg_disp1_emi_req_mask_b = 0x0,
158 	.reg_disp1_infra_req_mask_b = 0x0,
159 	.reg_disp1_pmic_req_mask_b = 0x0,
160 	.reg_disp1_srcclkena_mask_b = 0x0,
161 	.reg_disp1_vrf18_req_mask_b = 0x0,
162 	.reg_dpm_apsrc_req_mask_b = 0xf,
163 	.reg_dpm_ddren_req_mask_b = 0xf,
164 	.reg_dpm_emi_req_mask_b = 0xf,
165 	.reg_dpm_infra_req_mask_b = 0xf,
166 	.reg_dpm_pmic_req_mask_b = 0xf,
167 	.reg_dpm_srcclkena_mask_b = 0xf,
168 
169 	/* SPM_SRC_MASK_6 */
170 	.reg_dpm_vcore_req_mask_b = 0xf,
171 	.reg_dpm_vrf18_req_mask_b = 0xf,
172 	.reg_dpmaif_apsrc_req_mask_b = 0x1,
173 	.reg_dpmaif_ddren_req_mask_b = 0x1,
174 	.reg_dpmaif_emi_req_mask_b = 0x1,
175 	.reg_dpmaif_infra_req_mask_b = 0x1,
176 	.reg_dpmaif_pmic_req_mask_b = 0x1,
177 	.reg_dpmaif_srcclkena_mask_b = 0x1,
178 	.reg_dpmaif_vrf18_req_mask_b = 0x1,
179 	.reg_dvfsrc_level_req_mask_b = 0x1,
180 	.reg_emisys_apsrc_req_mask_b = 0x0,
181 	.reg_emisys_ddren_req_mask_b = 0x1,
182 	.reg_emisys_emi_req_mask_b = 0x0,
183 	.reg_gce_d_apsrc_req_mask_b = 0x1,
184 	.reg_gce_d_ddren_req_mask_b = 0x1,
185 	.reg_gce_d_emi_req_mask_b = 0x1,
186 	.reg_gce_d_infra_req_mask_b = 0x0,
187 	.reg_gce_d_pmic_req_mask_b = 0x0,
188 	.reg_gce_d_srcclkena_mask_b = 0x0,
189 	.reg_gce_d_vrf18_req_mask_b = 0x0,
190 	.reg_gce_m_apsrc_req_mask_b = 0x1,
191 	.reg_gce_m_ddren_req_mask_b = 0x1,
192 	.reg_gce_m_emi_req_mask_b = 0x1,
193 	.reg_gce_m_infra_req_mask_b = 0x0,
194 	.reg_gce_m_pmic_req_mask_b = 0x0,
195 	.reg_gce_m_srcclkena_mask_b = 0x0,
196 
197 	/* SPM_SRC_MASK_7 */
198 	.reg_gce_m_vrf18_req_mask_b = 0x0,
199 	.reg_gpueb_apsrc_req_mask_b = 0x0,
200 	.reg_gpueb_ddren_req_mask_b = 0x0,
201 	.reg_gpueb_emi_req_mask_b = 0x0,
202 	.reg_gpueb_infra_req_mask_b = 0x0,
203 	.reg_gpueb_pmic_req_mask_b = 0x0,
204 	.reg_gpueb_srcclkena_mask_b = 0x0,
205 	.reg_gpueb_vrf18_req_mask_b = 0x0,
206 	.reg_hwccf_apsrc_req_mask_b = 0x1,
207 	.reg_hwccf_ddren_req_mask_b = 0x1,
208 	.reg_hwccf_emi_req_mask_b = 0x1,
209 	.reg_hwccf_infra_req_mask_b = 0x1,
210 	.reg_hwccf_pmic_req_mask_b = 0x1,
211 	.reg_hwccf_srcclkena_mask_b = 0x1,
212 	.reg_hwccf_vcore_req_mask_b = 0x1,
213 	.reg_hwccf_vrf18_req_mask_b = 0x1,
214 	.reg_img_apsrc_req_mask_b = 0x1,
215 	.reg_img_ddren_req_mask_b = 0x1,
216 	.reg_img_emi_req_mask_b = 0x1,
217 	.reg_img_infra_req_mask_b = 0x0,
218 	.reg_img_pmic_req_mask_b = 0x0,
219 	.reg_img_srcclkena_mask_b = 0x0,
220 	.reg_img_vrf18_req_mask_b = 0x0,
221 	.reg_infrasys_apsrc_req_mask_b = 0x1,
222 	.reg_infrasys_ddren_req_mask_b = 0x1,
223 	.reg_infrasys_emi_req_mask_b = 0x1,
224 	.reg_ipic_infra_req_mask_b = 0x1,
225 	.reg_ipic_vrf18_req_mask_b = 0x1,
226 	.reg_mcu_apsrc_req_mask_b = 0x0,
227 	.reg_mcu_ddren_req_mask_b = 0x0,
228 	.reg_mcu_emi_req_mask_b = 0x0,
229 
230 	/* SPM_SRC_MASK_8 */
231 	.reg_mcusys_apsrc_req_mask_b = 0x7,
232 	.reg_mcusys_ddren_req_mask_b = 0x7,
233 	.reg_mcusys_emi_req_mask_b = 0x7,
234 	.reg_mcusys_infra_req_mask_b = 0x0,
235 
236 	/* SPM_SRC_MASK_9 */
237 	.reg_mcusys_pmic_req_mask_b = 0x0,
238 	.reg_mcusys_srcclkena_mask_b = 0x0,
239 	.reg_mcusys_vrf18_req_mask_b = 0x0,
240 	.reg_md_apsrc_req_mask_b = 0x0,
241 	.reg_md_ddren_req_mask_b = 0x0,
242 	.reg_md_emi_req_mask_b = 0x0,
243 	.reg_md_infra_req_mask_b = 0x0,
244 	.reg_md_pmic_req_mask_b = 0x0,
245 	.reg_md_srcclkena_mask_b = 0x0,
246 	.reg_md_srcclkena1_mask_b = 0x0,
247 	.reg_md_vcore_req_mask_b = 0x0,
248 
249 	/* SPM_SRC_MASK_10 */
250 	.reg_md_vrf18_req_mask_b = 0x0,
251 	.reg_mdp_apsrc_req_mask_b = 0x0,
252 	.reg_mdp_ddren_req_mask_b = 0x0,
253 	.reg_mm_proc_apsrc_req_mask_b = 0x0,
254 	.reg_mm_proc_ddren_req_mask_b = 0x0,
255 	.reg_mm_proc_emi_req_mask_b = 0x0,
256 	.reg_mm_proc_infra_req_mask_b = 0x0,
257 	.reg_mm_proc_pmic_req_mask_b = 0x0,
258 	.reg_mm_proc_srcclkena_mask_b = 0x0,
259 	.reg_mm_proc_vrf18_req_mask_b = 0x0,
260 	.reg_mmsys_apsrc_req_mask_b = 0x0,
261 	.reg_mmsys_ddren_req_mask_b = 0x0,
262 	.reg_mmsys_vrf18_req_mask_b = 0x0,
263 	.reg_pcie0_apsrc_req_mask_b = 0x0,
264 	.reg_pcie0_ddren_req_mask_b = 0x0,
265 	.reg_pcie0_infra_req_mask_b = 0x0,
266 	.reg_pcie0_srcclkena_mask_b = 0x0,
267 	.reg_pcie0_vrf18_req_mask_b = 0x0,
268 	.reg_pcie1_apsrc_req_mask_b = 0x0,
269 	.reg_pcie1_ddren_req_mask_b = 0x0,
270 	.reg_pcie1_infra_req_mask_b = 0x0,
271 	.reg_pcie1_srcclkena_mask_b = 0x0,
272 	.reg_pcie1_vrf18_req_mask_b = 0x0,
273 	.reg_perisys_apsrc_req_mask_b = 0x1,
274 	.reg_perisys_ddren_req_mask_b = 0x1,
275 	.reg_perisys_emi_req_mask_b = 0x1,
276 	.reg_perisys_infra_req_mask_b = 0x1,
277 	.reg_perisys_pmic_req_mask_b = 0x1,
278 	.reg_perisys_srcclkena_mask_b = 0x1,
279 	.reg_perisys_vcore_req_mask_b = 0x1,
280 	.reg_perisys_vrf18_req_mask_b = 0x1,
281 	.reg_scp_apsrc_req_mask_b = 0x1,
282 
283 	/* SPM_SRC_MASK_11 */
284 	.reg_scp_ddren_req_mask_b = 0x1,
285 	.reg_scp_emi_req_mask_b = 0x1,
286 	.reg_scp_infra_req_mask_b = 0x1,
287 	.reg_scp_pmic_req_mask_b = 0x1,
288 	.reg_scp_srcclkena_mask_b = 0x1,
289 	.reg_scp_vcore_req_mask_b = 0x1,
290 	.reg_scp_vrf18_req_mask_b = 0x1,
291 	.reg_srcclkeni_infra_req_mask_b = 0x1,
292 	.reg_srcclkeni_pmic_req_mask_b = 0x1,
293 	.reg_srcclkeni_srcclkena_mask_b = 0x1,
294 	.reg_sspm_apsrc_req_mask_b = 0x1,
295 	.reg_sspm_ddren_req_mask_b = 0x1,
296 	.reg_sspm_emi_req_mask_b = 0x1,
297 	.reg_sspm_infra_req_mask_b = 0x1,
298 	.reg_sspm_pmic_req_mask_b = 0x1,
299 	.reg_sspm_srcclkena_mask_b = 0x1,
300 	.reg_sspm_vrf18_req_mask_b = 0x1,
301 	.reg_ssr_apsrc_req_mask_b = 0x0,
302 	.reg_ssr_ddren_req_mask_b = 0x0,
303 	.reg_ssr_emi_req_mask_b = 0x0,
304 	.reg_ssr_infra_req_mask_b = 0x0,
305 	.reg_ssr_pmic_req_mask_b = 0x0,
306 	.reg_ssr_srcclkena_mask_b = 0x0,
307 	.reg_ssr_vrf18_req_mask_b = 0x0,
308 	.reg_ufs_apsrc_req_mask_b = 0x1,
309 	.reg_ufs_ddren_req_mask_b = 0x1,
310 	.reg_ufs_emi_req_mask_b = 0x1,
311 	.reg_ufs_infra_req_mask_b = 0x1,
312 	.reg_ufs_pmic_req_mask_b = 0x1,
313 
314 	/* SPM_SRC_MASK_12 */
315 	.reg_ufs_srcclkena_mask_b = 0x1,
316 	.reg_ufs_vrf18_req_mask_b = 0x1,
317 	.reg_vdec_apsrc_req_mask_b = 0x1,
318 	.reg_vdec_ddren_req_mask_b = 0x1,
319 	.reg_vdec_emi_req_mask_b = 0x1,
320 	.reg_vdec_infra_req_mask_b = 0x0,
321 	.reg_vdec_pmic_req_mask_b = 0x0,
322 	.reg_vdec_srcclkena_mask_b = 0x0,
323 	.reg_vdec_vrf18_req_mask_b = 0x0,
324 	.reg_venc_apsrc_req_mask_b = 0x1,
325 	.reg_venc_ddren_req_mask_b = 0x1,
326 	.reg_venc_emi_req_mask_b = 0x1,
327 	.reg_venc_infra_req_mask_b = 0x0,
328 	.reg_venc_pmic_req_mask_b = 0x0,
329 	.reg_venc_srcclkena_mask_b = 0x0,
330 	.reg_venc_vrf18_req_mask_b = 0x0,
331 	.reg_ipe_apsrc_req_mask_b = 0x1,
332 	.reg_ipe_ddren_req_mask_b = 0x1,
333 	.reg_ipe_emi_req_mask_b = 0x1,
334 	.reg_ipe_infra_req_mask_b = 0x1,
335 	.reg_ipe_pmic_req_mask_b = 0x1,
336 	.reg_ipe_srcclkena_mask_b = 0x1,
337 	.reg_ipe_vrf18_req_mask_b = 0x1,
338 	.reg_ufs_vcore_req_mask_b = 0x1,
339 
340 	/* SPM_EVENT_CON_MISC */
341 	.reg_srcclken_fast_resp = 0,
342 	.reg_csyspwrup_ack_mask = 1,
343 
344 	/* Auto-gen End */
345 
346 	/* SPM_WAKEUP_EVENT_MASK */
347 	.reg_wakeup_event_mask = 0xC1B33012,
348 
349 	/* SPM_WAKEUP_EVENT_EXT_MASK */
350 	.reg_ext_wakeup_event_mask = 0xFFFFFFFF,
351 };
352 
353 static struct dbg_ctrl idle_spm_dbg = {
354 	.count = 0,
355 	.duration = 0,
356 	.ext = NULL,
357 };
358 
359 static struct spm_lp_stat idle_lp_stat;
360 
361 static struct spm_lp_scen idle_spm_lp = {
362 	.pwrctrl = &idle_spm_pwr,
363 	.dbgctrl = &idle_spm_dbg,
364 	.lpstat = &idle_lp_stat,
365 };
366 
mt_spm_idle_generic_enter(int state_id,uint32_t ext_opand,spm_idle_conduct fn)367 int mt_spm_idle_generic_enter(int state_id, uint32_t ext_opand,
368 			      spm_idle_conduct fn)
369 {
370 	int ret = 0;
371 	uint32_t src_req = 0;
372 	struct mt_lp_publish_event event = {
373 		.id = MT_LPM_PUBEVENTS_SYS_POWER_OFF,
374 		.val.u32 = 0,
375 		.level = 0,
376 	};
377 
378 	if (fn)
379 		fn(state_id, &idle_spm_lp, &src_req);
380 
381 	ret = spm_conservation(state_id, ext_opand, &idle_spm_lp, src_req);
382 
383 	if (ret) {
384 		NOTICE("[%s:%d] - unknown issue !!\n", __func__, __LINE__);
385 		panic();
386 	}
387 
388 	if (ext_opand & MT_SPM_EX_OP_DEVICES_SAVE) {
389 		mmio_write_32(SPM2SW_MAILBOX_0, 0x1);
390 		MT_LP_SUSPEND_PUBLISH_EVENT(&event);
391 	} else
392 		MT_LP_PUBLISH_EVENT(&event);
393 	return ret;
394 }
395 
mt_spm_idle_generic_resume(int state_id,uint32_t ext_opand,struct wake_status ** status,spm_idle_conduct_restore fn)396 void mt_spm_idle_generic_resume(int state_id, uint32_t ext_opand,
397 				struct wake_status **status,
398 				spm_idle_conduct_restore fn)
399 {
400 	struct mt_lp_publish_event event = {
401 		.id = MT_LPM_PUBEVENTS_SYS_POWER_ON,
402 		.val.u32 = 0,
403 	};
404 
405 	ext_opand |= (MT_SPM_EX_OP_TIME_CHECK | MT_SPM_EX_OP_TIME_OBS);
406 	spm_conservation_finish(state_id, ext_opand, &idle_spm_lp, status);
407 
408 	mt_spm_update_lp_stat(&idle_lp_stat);
409 
410 	if (spm_unlikely(fn))
411 		fn(state_id, &idle_spm_lp, *status);
412 
413 	if (ext_opand & MT_SPM_EX_OP_DEVICES_SAVE) {
414 		mmio_write_32(SPM2SW_MAILBOX_0, 0x0);
415 		MT_LP_SUSPEND_PUBLISH_EVENT(&event);
416 	} else
417 		MT_LP_PUBLISH_EVENT(&event);
418 }
419 
mt_spm_idle_generic_get_spm_lp(struct spm_lp_scen ** lp)420 int mt_spm_idle_generic_get_spm_lp(struct spm_lp_scen **lp)
421 {
422 	if (!lp)
423 		return -1;
424 
425 	*lp = &idle_spm_lp;
426 	return 0;
427 }
428