2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
17 #include <console/console.h>
19 #include <device/mmio.h>
25 #define BUF_SIZE (16 * KiB)
26 static uint8_t spm_bin
[BUF_SIZE
] __aligned(8);
28 static int spm_register_init(void)
32 write32(&mtk_spm
->poweron_config_set
,
33 SPM_REGWR_CFG_KEY
| BCLK_CG_EN_LSB
| MD_BCLK_CG_EN_LSB
);
35 write32(&mtk_spm
->spm_power_on_val1
, POWER_ON_VAL1_DEF
);
36 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
38 write32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
|
40 write32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
);
42 pcm_fsm_sta
= read32(&mtk_spm
->pcm_fsm_sta
);
44 if ((pcm_fsm_sta
& PCM_FSM_STA_MASK
) != PCM_FSM_STA_DEF
) {
45 printk(BIOS_ERR
, "PCM reset failed\n");
49 write32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
|
51 write32(&mtk_spm
->pcm_con1
, SPM_REGWR_CFG_KEY
| EVENT_LOCK_EN_LSB
|
52 SPM_SRAM_ISOINT_B_LSB
| MIF_APBEN_LSB
|
53 SCP_APB_INTERNAL_EN_LSB
);
54 write32(&mtk_spm
->pcm_im_ptr
, 0);
55 write32(&mtk_spm
->pcm_im_len
, 0);
57 write32(&mtk_spm
->spm_clk_con
,
58 read32(&mtk_spm
->spm_clk_con
) | SYSCLK1_EN_CTRL
|
59 SPM_LOCK_INFRA_DCM_LSB
| EXT_SRCCLKEN_MASK
|
60 CXO32K_REMOVE_EN_MD1_LSB
|
61 CLKSQ1_SEL_CTRL_LSB
| SRCLKEN0_EN_LSB
| SYSCLK1_SRC_MASK_B
);
63 write32(&mtk_spm
->spm_wakeup_event_mask
, SPM_WAKEUP_EVENT_MASK_DEF
);
65 write32(&mtk_spm
->spm_irq_mask
, ISRM_ALL
);
66 write32(&mtk_spm
->spm_irq_sta
, ISRC_ALL
);
67 write32(&mtk_spm
->spm_swint_clr
, PCM_SW_INT_ALL
);
69 write32(&mtk_spm
->pcm_reg_data_ini
,
70 read32(&mtk_spm
->spm_power_on_val1
));
71 write32(&mtk_spm
->pcm_pwr_io_en
, PCM_RF_SYNC_R7
);
72 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
74 write32(&mtk_spm
->ddr_en_dbc_len
,
79 clrsetbits32(&mtk_spm
->spare_ack_mask
,
80 SPARE_ACK_MASK_B_BIT1
,
81 SPARE_ACK_MASK_B_BIT0
);
83 write32(&mtk_spm
->sysrom_con
, IFR_SRAMROM_ROM_PDN
);
84 write32(&mtk_spm
->spm_pc_trace_con
,
86 SPM_PC_TRACE_HW_EN_LSB
);
88 setbits32(&mtk_spm
->spare_src_req_mask
, SPARE1_DDREN_MASK_B_LSB
);
93 static int spm_code_swapping(void)
97 con1
= read32(&mtk_spm
->spm_wakeup_event_mask
);
99 write32(&mtk_spm
->spm_wakeup_event_mask
,
100 con1
& ~WAKEUP_EVENT_MASK_B_BIT0
);
101 write32(&mtk_spm
->spm_cpu_wakeup_event
, 1);
103 if (!wait_us(SPM_CORE_TIMEOUT
,
104 read32(&mtk_spm
->spm_irq_sta
) & PCM_IRQ_ROOT_MASK_LSB
)) {
106 "timeout: r15=%#x, pcmsta=%#x, irqsta=%#x [%d]\n",
107 read32(&mtk_spm
->pcm_reg15_data
),
108 read32(&mtk_spm
->pcm_fsm_sta
),
109 read32(&mtk_spm
->spm_irq_sta
),
114 write32(&mtk_spm
->spm_cpu_wakeup_event
, 0);
115 write32(&mtk_spm
->spm_wakeup_event_mask
, con1
);
119 static int spm_reset_and_init_pcm(const struct pcm_desc
*pcmdesc
)
121 u32 con1
, pcm_fsm_sta
;
123 if (read32(&mtk_spm
->pcm_reg1_data
) == SPM_PCM_REG1_DATA_CHECK
&&
124 read32(&mtk_spm
->pcm_reg15_data
) != SPM_PCM_REG15_DATA_CHECK
) {
125 if (spm_code_swapping())
127 write32(&mtk_spm
->spm_power_on_val0
,
128 read32(&mtk_spm
->pcm_reg0_data
));
131 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
133 clrsetbits32(&mtk_spm
->pcm_con1
,
137 write32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
|
139 write32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
);
141 pcm_fsm_sta
= read32(&mtk_spm
->pcm_fsm_sta
);
143 if ((pcm_fsm_sta
& PCM_FSM_STA_MASK
) != PCM_FSM_STA_DEF
) {
144 printk(BIOS_ERR
, "reset pcm(PCM_FSM_STA=%#x)\n",
145 read32(&mtk_spm
->pcm_fsm_sta
));
149 write32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
|
150 EN_IM_SLEEP_DVS_LSB
);
152 con1
= read32(&mtk_spm
->pcm_con1
) & PCM_WDT_WAKE_MODE_LSB
;
153 write32(&mtk_spm
->pcm_con1
, con1
| SPM_REGWR_CFG_KEY
|
154 EVENT_LOCK_EN_LSB
| SPM_SRAM_ISOINT_B_LSB
|
155 (pcmdesc
->replace
? 0 : IM_NONRP_EN_LSB
) |
156 MIF_APBEN_LSB
| SCP_APB_INTERNAL_EN_LSB
);
161 static void spm_load_pcm_code(const struct dyna_load_pcm
*pcm
)
165 write32(&mtk_spm
->pcm_con1
, read32(&mtk_spm
->pcm_con1
) |
166 SPM_REGWR_CFG_KEY
| IM_SLAVE_LSB
);
168 for (i
= 0; i
< pcm
->desc
.size
; i
++) {
169 write32(&mtk_spm
->pcm_im_host_rw_ptr
,
170 PCM_IM_HOST_EN_LSB
| PCM_IM_HOST_W_EN_LSB
| i
);
171 write32(&mtk_spm
->pcm_im_host_rw_dat
,
172 (u32
) *(pcm
->buf
+ i
));
174 write32(&mtk_spm
->pcm_im_host_rw_ptr
, 0);
177 static void spm_check_pcm_code(const struct dyna_load_pcm
*pcm
)
181 for (i
= 0; i
< pcm
->desc
.size
; i
++) {
182 write32(&mtk_spm
->pcm_im_host_rw_ptr
, PCM_IM_HOST_EN_LSB
| i
);
183 if ((read32(&mtk_spm
->pcm_im_host_rw_dat
)) !=
184 (u32
) *(pcm
->buf
+ i
))
185 spm_load_pcm_code(pcm
);
187 write32(&mtk_spm
->pcm_im_host_rw_ptr
, 0);
190 static void spm_kick_im_to_fetch(const struct dyna_load_pcm
*pcm
)
194 spm_load_pcm_code(pcm
);
195 spm_check_pcm_code(pcm
);
197 printk(BIOS_DEBUG
, "%s: ptr = %p\n", __func__
, pcm
->buf
);
198 printk(BIOS_DEBUG
, "%s: len = %d\n", __func__
, pcm
->desc
.size
);
200 con0
= read32(&mtk_spm
->pcm_con0
) & ~(IM_KICK_L_LSB
| PCM_KICK_L_LSB
);
201 write32(&mtk_spm
->pcm_con0
, con0
| SPM_REGWR_CFG_KEY
|
202 PCM_CK_EN_LSB
| IM_KICK_L_LSB
);
203 write32(&mtk_spm
->pcm_con0
, con0
| SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
);
206 static void spm_init_pcm_register(void)
208 write32(&mtk_spm
->pcm_reg_data_ini
,
209 read32(&mtk_spm
->spm_power_on_val0
));
210 write32(&mtk_spm
->pcm_pwr_io_en
, PCM_RF_SYNC_R0
);
211 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
213 write32(&mtk_spm
->pcm_reg_data_ini
,
214 read32(&mtk_spm
->spm_power_on_val1
));
215 write32(&mtk_spm
->pcm_pwr_io_en
, PCM_RF_SYNC_R7
);
216 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
219 static void spm_init_event_vector(const struct pcm_desc
*pcmdesc
)
221 for (int i
= 0; i
< PCM_EVENT_VECTOR_NUM
; i
++)
222 write32(&mtk_spm
->pcm_event_vector
[i
], pcmdesc
->vector
[i
]);
225 static const char * const dyna_load_pcm_path
[] = {
226 [DYNA_LOAD_PCM_SUSPEND_LP4_3733
] = "pcm_allinone_lp4_3733.bin",
227 [DYNA_LOAD_PCM_SUSPEND_LP4_3200
] = "pcm_allinone_lp4_3200.bin",
230 static int spm_load_firmware(enum dyna_load_pcm_index index
,
231 struct dyna_load_pcm
*pcm
)
236 * u32 binary[firmware_size]
237 * struct pcm_desc descriptor
242 const char *file_name
= dyna_load_pcm_path
[index
];
247 size_t file_size
= cbfs_boot_load_file(file_name
, spm_bin
,
248 sizeof(spm_bin
), CBFS_TYPE_RAW
);
250 if (file_size
== 0) {
251 printk(BIOS_ERR
, "SPM binary %s not found\n", file_name
);
258 copy_size
= sizeof(firmware_size
);
259 memcpy(&firmware_size
, spm_bin
+ offset
, copy_size
);
260 printk(BIOS_DEBUG
, "SPM: binary array size = %d\n", firmware_size
);
264 assert(offset
< file_size
);
265 copy_size
= firmware_size
* 4;
266 pcm
->buf
= (u32
*)(spm_bin
+ offset
);
270 assert(offset
< file_size
);
271 copy_size
= sizeof(struct pcm_desc
);
272 memcpy((void *)&(pcm
->desc
.size
), spm_bin
+ offset
, copy_size
);
276 /* The terminating character should be contained in the spm binary */
277 assert(spm_bin
[file_size
- 1] == '\0');
278 assert(offset
< file_size
);
279 printk(BIOS_DEBUG
, "SPM: version = %s\n", spm_bin
+ offset
);
281 printk(BIOS_INFO
, "SPM binary loaded in %ld msecs\n",
282 stopwatch_duration_msecs(&sw
));
287 static void spm_kick_pcm_to_run(void)
291 write32(&mtk_spm
->spm_mas_pause_mask_b
, SPM_MAS_PAUSE_MASK_B_VAL
);
292 write32(&mtk_spm
->spm_mas_pause2_mask_b
, SPM_MAS_PAUSE2_MASK_B_VAL
);
293 write32(&mtk_spm
->pcm_reg_data_ini
, 0);
295 write32(&mtk_spm
->pcm_pwr_io_en
, PCM_PWRIO_EN_R0
| PCM_PWRIO_EN_R7
);
297 printk(BIOS_DEBUG
, "SPM: %s\n", __func__
);
300 while ((read32(&mtk_spm
->pcm_fsm_sta
) & IM_STATE_MASK
) != IM_STATE
)
303 /* kick PCM to run, and toggle PCM_KICK */
304 con0
= read32(&mtk_spm
->pcm_con0
) & ~(IM_KICK_L_LSB
| PCM_KICK_L_LSB
);
305 write32(&mtk_spm
->pcm_con0
, con0
| SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
|
307 write32(&mtk_spm
->pcm_con0
, con0
| SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
);
309 printk(BIOS_DEBUG
, "SPM: %s done\n", __func__
);
314 struct pcm_desc
*pcmdesc
;
315 enum dyna_load_pcm_index index
;
320 if (CONFIG(MT8183_DRAM_EMCP
))
321 index
= DYNA_LOAD_PCM_SUSPEND_LP4_3733
;
323 index
= DYNA_LOAD_PCM_SUSPEND_LP4_3200
;
325 printk(BIOS_DEBUG
, "SPM: pcm index = %d\n", index
);
327 struct dyna_load_pcm pcm
;
328 if (spm_load_firmware(index
, &pcm
)) {
329 printk(BIOS_ERR
, "SPM: firmware is not ready\n");
330 printk(BIOS_ERR
, "SPM: check dram type and firmware version\n");
336 if (spm_register_init())
339 if (spm_reset_and_init_pcm(pcmdesc
))
342 spm_kick_im_to_fetch(&pcm
);
343 spm_init_pcm_register();
344 spm_init_event_vector(pcmdesc
);
345 spm_kick_pcm_to_run();
347 printk(BIOS_INFO
, "SPM: %s done in %ld msecs\n", __func__
,
348 stopwatch_duration_msecs(&sw
));