blob: e35fc57e2fd4ac783beb8fd49c81a01429725a2a [file] [log] [blame]
Angel Ponse67ab182020-04-04 18:51:11 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Dawei Chien2422f8c2019-05-30 11:55:10 +08002
3#include <assert.h>
4#include <cbfs.h>
Elyes HAOUAS23846822019-10-30 09:07:51 +01005#include <console/console.h>
Dawei Chien2422f8c2019-05-30 11:55:10 +08006#include <device/mmio.h>
7#include <endian.h>
8#include <soc/emi.h>
9#include <soc/spm.h>
10#include <timer.h>
11
12#define BUF_SIZE (16 * KiB)
13static uint8_t spm_bin[BUF_SIZE] __aligned(8);
14
15static int spm_register_init(void)
16{
17 u32 pcm_fsm_sta;
18
19 write32(&mtk_spm->poweron_config_set,
20 SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB | MD_BCLK_CG_EN_LSB);
21
22 write32(&mtk_spm->spm_power_on_val1, POWER_ON_VAL1_DEF);
23 write32(&mtk_spm->pcm_pwr_io_en, 0);
24
25 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
26 PCM_SW_RESET_LSB);
27 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
28
29 pcm_fsm_sta = read32(&mtk_spm->pcm_fsm_sta);
30
31 if ((pcm_fsm_sta & PCM_FSM_STA_MASK) != PCM_FSM_STA_DEF) {
32 printk(BIOS_ERR, "PCM reset failed\n");
33 return -1;
34 }
35
36 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
37 EN_IM_SLEEP_DVS_LSB);
38 write32(&mtk_spm->pcm_con1, SPM_REGWR_CFG_KEY | EVENT_LOCK_EN_LSB |
39 SPM_SRAM_ISOINT_B_LSB | MIF_APBEN_LSB |
40 SCP_APB_INTERNAL_EN_LSB);
41 write32(&mtk_spm->pcm_im_ptr, 0);
42 write32(&mtk_spm->pcm_im_len, 0);
43
44 write32(&mtk_spm->spm_clk_con,
45 read32(&mtk_spm->spm_clk_con) | SYSCLK1_EN_CTRL |
46 SPM_LOCK_INFRA_DCM_LSB | EXT_SRCCLKEN_MASK |
47 CXO32K_REMOVE_EN_MD1_LSB |
48 CLKSQ1_SEL_CTRL_LSB | SRCLKEN0_EN_LSB | SYSCLK1_SRC_MASK_B);
49
50 write32(&mtk_spm->spm_wakeup_event_mask, SPM_WAKEUP_EVENT_MASK_DEF);
51
52 write32(&mtk_spm->spm_irq_mask, ISRM_ALL);
53 write32(&mtk_spm->spm_irq_sta, ISRC_ALL);
54 write32(&mtk_spm->spm_swint_clr, PCM_SW_INT_ALL);
55
56 write32(&mtk_spm->pcm_reg_data_ini,
57 read32(&mtk_spm->spm_power_on_val1));
58 write32(&mtk_spm->pcm_pwr_io_en, PCM_RF_SYNC_R7);
59 write32(&mtk_spm->pcm_pwr_io_en, 0);
60
61 write32(&mtk_spm->ddr_en_dbc_len,
62 MD_DDR_EN_0_DBC_LEN |
63 MD_DDR_EN_1_DBC_LEN |
64 CONN_DDR_EN_DBC_LEN);
65
Julius Werner55009af2019-12-02 22:03:27 -080066 clrsetbits32(&mtk_spm->spare_ack_mask,
67 SPARE_ACK_MASK_B_BIT1,
68 SPARE_ACK_MASK_B_BIT0);
Dawei Chien2422f8c2019-05-30 11:55:10 +080069
70 write32(&mtk_spm->sysrom_con, IFR_SRAMROM_ROM_PDN);
71 write32(&mtk_spm->spm_pc_trace_con,
72 SPM_PC_TRACE_OFFSET |
73 SPM_PC_TRACE_HW_EN_LSB);
74
Julius Werner55009af2019-12-02 22:03:27 -080075 setbits32(&mtk_spm->spare_src_req_mask, SPARE1_DDREN_MASK_B_LSB);
Dawei Chien2422f8c2019-05-30 11:55:10 +080076
77 return 0;
78}
79
80static int spm_code_swapping(void)
81{
82 u32 con1;
83
84 con1 = read32(&mtk_spm->spm_wakeup_event_mask);
85
86 write32(&mtk_spm->spm_wakeup_event_mask,
87 con1 & ~WAKEUP_EVENT_MASK_B_BIT0);
88 write32(&mtk_spm->spm_cpu_wakeup_event, 1);
89
90 if (!wait_us(SPM_CORE_TIMEOUT,
91 read32(&mtk_spm->spm_irq_sta) & PCM_IRQ_ROOT_MASK_LSB)) {
92 printk(BIOS_ERR,
93 "timeout: r15=%#x, pcmsta=%#x, irqsta=%#x [%d]\n",
94 read32(&mtk_spm->pcm_reg15_data),
95 read32(&mtk_spm->pcm_fsm_sta),
96 read32(&mtk_spm->spm_irq_sta),
97 SPM_CORE_TIMEOUT);
98 return -1;
99 }
100
101 write32(&mtk_spm->spm_cpu_wakeup_event, 0);
102 write32(&mtk_spm->spm_wakeup_event_mask, con1);
103 return 0;
104}
105
106static int spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc)
107{
108 u32 con1, pcm_fsm_sta;
109
110 if (read32(&mtk_spm->pcm_reg1_data) == SPM_PCM_REG1_DATA_CHECK &&
111 read32(&mtk_spm->pcm_reg15_data) != SPM_PCM_REG15_DATA_CHECK) {
112 if (spm_code_swapping())
113 return -1;
114 write32(&mtk_spm->spm_power_on_val0,
115 read32(&mtk_spm->pcm_reg0_data));
116 }
117
118 write32(&mtk_spm->pcm_pwr_io_en, 0);
119
Julius Werner55009af2019-12-02 22:03:27 -0800120 clrsetbits32(&mtk_spm->pcm_con1,
121 PCM_TIMER_EN_LSB,
122 SPM_REGWR_CFG_KEY);
Dawei Chien2422f8c2019-05-30 11:55:10 +0800123
124 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
125 PCM_SW_RESET_LSB);
126 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
127
128 pcm_fsm_sta = read32(&mtk_spm->pcm_fsm_sta);
129
130 if ((pcm_fsm_sta & PCM_FSM_STA_MASK) != PCM_FSM_STA_DEF) {
131 printk(BIOS_ERR, "reset pcm(PCM_FSM_STA=%#x)\n",
132 read32(&mtk_spm->pcm_fsm_sta));
133 return -1;
134 }
135
136 write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
137 EN_IM_SLEEP_DVS_LSB);
138
139 con1 = read32(&mtk_spm->pcm_con1) & PCM_WDT_WAKE_MODE_LSB;
140 write32(&mtk_spm->pcm_con1, con1 | SPM_REGWR_CFG_KEY |
141 EVENT_LOCK_EN_LSB | SPM_SRAM_ISOINT_B_LSB |
142 (pcmdesc->replace ? 0 : IM_NONRP_EN_LSB) |
143 MIF_APBEN_LSB | SCP_APB_INTERNAL_EN_LSB);
144
145 return 0;
146}
147
148static void spm_load_pcm_code(const struct dyna_load_pcm *pcm)
149{
150 int i;
151
152 write32(&mtk_spm->pcm_con1, read32(&mtk_spm->pcm_con1) |
153 SPM_REGWR_CFG_KEY | IM_SLAVE_LSB);
154
155 for (i = 0; i < pcm->desc.size; i++) {
156 write32(&mtk_spm->pcm_im_host_rw_ptr,
157 PCM_IM_HOST_EN_LSB | PCM_IM_HOST_W_EN_LSB | i);
158 write32(&mtk_spm->pcm_im_host_rw_dat,
159 (u32) *(pcm->buf + i));
160 }
161 write32(&mtk_spm->pcm_im_host_rw_ptr, 0);
162}
163
164static void spm_check_pcm_code(const struct dyna_load_pcm *pcm)
165{
166 int i;
167
168 for (i = 0; i < pcm->desc.size; i++) {
169 write32(&mtk_spm->pcm_im_host_rw_ptr, PCM_IM_HOST_EN_LSB | i);
170 if ((read32(&mtk_spm->pcm_im_host_rw_dat)) !=
171 (u32) *(pcm->buf + i))
172 spm_load_pcm_code(pcm);
173 }
174 write32(&mtk_spm->pcm_im_host_rw_ptr, 0);
175}
176
177static void spm_kick_im_to_fetch(const struct dyna_load_pcm *pcm)
178{
179 u32 con0;
180
181 spm_load_pcm_code(pcm);
182 spm_check_pcm_code(pcm);
183
184 printk(BIOS_DEBUG, "%s: ptr = %p\n", __func__, pcm->buf);
185 printk(BIOS_DEBUG, "%s: len = %d\n", __func__, pcm->desc.size);
186
187 con0 = read32(&mtk_spm->pcm_con0) & ~(IM_KICK_L_LSB | PCM_KICK_L_LSB);
188 write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY |
189 PCM_CK_EN_LSB | IM_KICK_L_LSB);
190 write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
191}
192
193static void spm_init_pcm_register(void)
194{
195 write32(&mtk_spm->pcm_reg_data_ini,
196 read32(&mtk_spm->spm_power_on_val0));
197 write32(&mtk_spm->pcm_pwr_io_en, PCM_RF_SYNC_R0);
198 write32(&mtk_spm->pcm_pwr_io_en, 0);
199
200 write32(&mtk_spm->pcm_reg_data_ini,
201 read32(&mtk_spm->spm_power_on_val1));
202 write32(&mtk_spm->pcm_pwr_io_en, PCM_RF_SYNC_R7);
203 write32(&mtk_spm->pcm_pwr_io_en, 0);
204}
205
206static void spm_init_event_vector(const struct pcm_desc *pcmdesc)
207{
208 for (int i = 0; i < PCM_EVENT_VECTOR_NUM; i++)
209 write32(&mtk_spm->pcm_event_vector[i], pcmdesc->vector[i]);
210}
211
212static const char * const dyna_load_pcm_path[] = {
213 [DYNA_LOAD_PCM_SUSPEND_LP4_3733] = "pcm_allinone_lp4_3733.bin",
214 [DYNA_LOAD_PCM_SUSPEND_LP4_3200] = "pcm_allinone_lp4_3200.bin",
215};
216
217static int spm_load_firmware(enum dyna_load_pcm_index index,
218 struct dyna_load_pcm *pcm)
219{
220 /*
221 * Layout:
222 * u16 firmware_size
223 * u32 binary[firmware_size]
224 * struct pcm_desc descriptor
225 * char *version
226 */
227 u16 firmware_size;
228 int copy_size;
229 const char *file_name = dyna_load_pcm_path[index];
230 struct stopwatch sw;
231
232 stopwatch_init(&sw);
233
Julius Werner834b3ec2020-03-04 16:52:08 -0800234 size_t file_size = cbfs_load(file_name, spm_bin, sizeof(spm_bin));
Dawei Chien2422f8c2019-05-30 11:55:10 +0800235
236 if (file_size == 0) {
237 printk(BIOS_ERR, "SPM binary %s not found\n", file_name);
238 return -1;
239 }
240
241 int offset = 0;
242
243 /* firmware size */
244 copy_size = sizeof(firmware_size);
245 memcpy(&firmware_size, spm_bin + offset, copy_size);
246 printk(BIOS_DEBUG, "SPM: binary array size = %d\n", firmware_size);
247 offset += copy_size;
248
249 /* binary */
250 assert(offset < file_size);
251 copy_size = firmware_size * 4;
252 pcm->buf = (u32 *)(spm_bin + offset);
253 offset += copy_size;
254
255 /* descriptor */
256 assert(offset < file_size);
257 copy_size = sizeof(struct pcm_desc);
258 memcpy((void *)&(pcm->desc.size), spm_bin + offset, copy_size);
259 offset += copy_size;
260
261 /* version */
Elyes HAOUAS1f220a92020-02-20 14:17:55 +0100262 /* The terminating character should be contained in the spm binary */
Dawei Chien2422f8c2019-05-30 11:55:10 +0800263 assert(spm_bin[file_size - 1] == '\0');
264 assert(offset < file_size);
265 printk(BIOS_DEBUG, "SPM: version = %s\n", spm_bin + offset);
266
267 printk(BIOS_INFO, "SPM binary loaded in %ld msecs\n",
268 stopwatch_duration_msecs(&sw));
269
270 return 0;
271}
272
273static void spm_kick_pcm_to_run(void)
274{
275 uint32_t con0;
276
277 write32(&mtk_spm->spm_mas_pause_mask_b, SPM_MAS_PAUSE_MASK_B_VAL);
278 write32(&mtk_spm->spm_mas_pause2_mask_b, SPM_MAS_PAUSE2_MASK_B_VAL);
279 write32(&mtk_spm->pcm_reg_data_ini, 0);
280
281 write32(&mtk_spm->pcm_pwr_io_en, PCM_PWRIO_EN_R0 | PCM_PWRIO_EN_R7);
282
283 printk(BIOS_DEBUG, "SPM: %s\n", __func__);
284
285 /* check IM ready */
286 while ((read32(&mtk_spm->pcm_fsm_sta) & IM_STATE_MASK) != IM_STATE)
287 ;
288
289 /* kick PCM to run, and toggle PCM_KICK */
290 con0 = read32(&mtk_spm->pcm_con0) & ~(IM_KICK_L_LSB | PCM_KICK_L_LSB);
291 write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
292 PCM_KICK_L_LSB);
293 write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
294
295 printk(BIOS_DEBUG, "SPM: %s done\n", __func__);
296}
297
298int spm_init(void)
299{
300 struct pcm_desc *pcmdesc;
301 enum dyna_load_pcm_index index;
302 struct stopwatch sw;
303
304 stopwatch_init(&sw);
305
306 if (CONFIG(MT8183_DRAM_EMCP))
307 index = DYNA_LOAD_PCM_SUSPEND_LP4_3733;
308 else
309 index = DYNA_LOAD_PCM_SUSPEND_LP4_3200;
310
311 printk(BIOS_DEBUG, "SPM: pcm index = %d\n", index);
312
313 struct dyna_load_pcm pcm;
314 if (spm_load_firmware(index, &pcm)) {
315 printk(BIOS_ERR, "SPM: firmware is not ready\n");
316 printk(BIOS_ERR, "SPM: check dram type and firmware version\n");
317 return -1;
318 }
319
320 pcmdesc = &pcm.desc;
321
322 if (spm_register_init())
323 return -1;
324
325 if (spm_reset_and_init_pcm(pcmdesc))
326 return -1;
327
328 spm_kick_im_to_fetch(&pcm);
329 spm_init_pcm_register();
330 spm_init_event_vector(pcmdesc);
331 spm_kick_pcm_to_run();
332
333 printk(BIOS_INFO, "SPM: %s done in %ld msecs\n", __func__,
334 stopwatch_duration_msecs(&sw));
335
336 return 0;
337}