soc: Remove copyright notices
[coreboot.git] / src / soc / mediatek / mt8183 / spm.c
blobca7a5adfafe51f34a9fa7249c3cc7b63782a4ae6
1 /*
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.
15 #include <assert.h>
16 #include <cbfs.h>
17 #include <console/console.h>
18 #include <delay.h>
19 #include <device/mmio.h>
20 #include <endian.h>
21 #include <soc/emi.h>
22 #include <soc/spm.h>
23 #include <timer.h>
25 #define BUF_SIZE (16 * KiB)
26 static uint8_t spm_bin[BUF_SIZE] __aligned(8);
28 static int spm_register_init(void)
30 u32 pcm_fsm_sta;
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 |
39 PCM_SW_RESET_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");
46 return -1;
49 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
50 EN_IM_SLEEP_DVS_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,
75 MD_DDR_EN_0_DBC_LEN |
76 MD_DDR_EN_1_DBC_LEN |
77 CONN_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,
85 SPM_PC_TRACE_OFFSET |
86 SPM_PC_TRACE_HW_EN_LSB);
88 setbits32(&mtk_spm->spare_src_req_mask, SPARE1_DDREN_MASK_B_LSB);
90 return 0;
93 static int spm_code_swapping(void)
95 u32 con1;
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)) {
105 printk(BIOS_ERR,
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),
110 SPM_CORE_TIMEOUT);
111 return -1;
114 write32(&mtk_spm->spm_cpu_wakeup_event, 0);
115 write32(&mtk_spm->spm_wakeup_event_mask, con1);
116 return 0;
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())
126 return -1;
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,
134 PCM_TIMER_EN_LSB,
135 SPM_REGWR_CFG_KEY);
137 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
138 PCM_SW_RESET_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));
146 return -1;
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);
158 return 0;
161 static void spm_load_pcm_code(const struct dyna_load_pcm *pcm)
163 int i;
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)
179 int i;
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)
192 u32 con0;
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)
234 * Layout:
235 * u16 firmware_size
236 * u32 binary[firmware_size]
237 * struct pcm_desc descriptor
238 * char *version
240 u16 firmware_size;
241 int copy_size;
242 const char *file_name = dyna_load_pcm_path[index];
243 struct stopwatch sw;
245 stopwatch_init(&sw);
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);
252 return -1;
255 int offset = 0;
257 /* firmware size */
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);
261 offset += copy_size;
263 /* binary */
264 assert(offset < file_size);
265 copy_size = firmware_size * 4;
266 pcm->buf = (u32 *)(spm_bin + offset);
267 offset += copy_size;
269 /* descriptor */
270 assert(offset < file_size);
271 copy_size = sizeof(struct pcm_desc);
272 memcpy((void *)&(pcm->desc.size), spm_bin + offset, copy_size);
273 offset += copy_size;
275 /* version */
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));
284 return 0;
287 static void spm_kick_pcm_to_run(void)
289 uint32_t con0;
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__);
299 /* check IM ready */
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 |
306 PCM_KICK_L_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__);
312 int spm_init(void)
314 struct pcm_desc *pcmdesc;
315 enum dyna_load_pcm_index index;
316 struct stopwatch sw;
318 stopwatch_init(&sw);
320 if (CONFIG(MT8183_DRAM_EMCP))
321 index = DYNA_LOAD_PCM_SUSPEND_LP4_3733;
322 else
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");
331 return -1;
334 pcmdesc = &pcm.desc;
336 if (spm_register_init())
337 return -1;
339 if (spm_reset_and_init_pcm(pcmdesc))
340 return -1;
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));
350 return 0;