1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
6 #include <soc/mcu_common.h>
8 #include <soc/symbols.h>
12 #define SPMFW_HEADER_SIZE 16
14 __weak
void spm_extern_initialize(void) { /* do nothing */ }
16 static void spm_set_sysclk_settle(void)
18 write32(&mtk_spm
->spm_clk_settle
, SPM_SYSCLK_SETTLE
);
21 static void spm_kick_im_to_fetch(const struct dyna_load_pcm
*pcm
)
30 ptr
= (uintptr_t)pcm
->buf
+ SPM_SYSTEM_BASE_OFFSET
;
31 pmem_words
= pcm
->desc
.pmem_words
;
32 total_words
= pcm
->desc
.total_words
;
33 dmem_words
= total_words
- pmem_words
;
34 pmem_start
= pcm
->desc
.pmem_start
;
35 dmem_start
= pcm
->desc
.dmem_start
;
37 printk(BIOS_DEBUG
, "%s: ptr = %#lx, pmem/dmem words = %#x/%#x\n",
38 __func__
, (long)ptr
, pmem_words
, dmem_words
);
40 /* DMA needs 16-byte aligned source data. */
41 assert(ptr
% 16 == 0);
43 write32(&mtk_spm
->md32pcm_dma0_src
, ptr
);
44 write32(&mtk_spm
->md32pcm_dma0_dst
, pmem_start
);
45 write32(&mtk_spm
->md32pcm_dma0_wppt
, pmem_words
);
46 write32(&mtk_spm
->md32pcm_dma0_wpto
, dmem_start
);
47 write32(&mtk_spm
->md32pcm_dma0_count
, total_words
);
48 write32(&mtk_spm
->md32pcm_dma0_con
, MD32PCM_DMA0_CON_VAL
);
49 write32(&mtk_spm
->md32pcm_dma0_start
, MD32PCM_DMA0_START_VAL
);
51 setbits32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
);
54 static void spm_init_pcm_register(void)
56 /* Init r0 with POWER_ON_VAL0 */
57 write32(&mtk_spm
->pcm_reg_data_ini
,
58 read32(&mtk_spm
->spm_power_on_val0
));
59 write32(&mtk_spm
->pcm_pwr_io_en
, PCM_RF_SYNC_R0
);
60 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
62 /* Init r7 with POWER_ON_VAL1 */
63 write32(&mtk_spm
->pcm_reg_data_ini
,
64 read32(&mtk_spm
->spm_power_on_val1
));
65 write32(&mtk_spm
->pcm_pwr_io_en
, PCM_RF_SYNC_R7
);
66 write32(&mtk_spm
->pcm_pwr_io_en
, 0);
69 static void spm_set_pcm_flags(const struct pwr_ctrl
*pwrctrl
)
71 u32 pcm_flags
= pwrctrl
->pcm_flags
, pcm_flags1
= pwrctrl
->pcm_flags1
;
73 /* Set PCM flags and data */
74 if (pwrctrl
->pcm_flags_cust_clr
!= 0)
75 pcm_flags
&= ~pwrctrl
->pcm_flags_cust_clr
;
76 if (pwrctrl
->pcm_flags_cust_set
!= 0)
77 pcm_flags
|= pwrctrl
->pcm_flags_cust_set
;
78 if (pwrctrl
->pcm_flags1_cust_clr
!= 0)
79 pcm_flags1
&= ~pwrctrl
->pcm_flags1_cust_clr
;
80 if (pwrctrl
->pcm_flags1_cust_set
!= 0)
81 pcm_flags1
|= pwrctrl
->pcm_flags1_cust_set
;
83 write32(&mtk_spm
->spm_sw_flag_0
, pcm_flags
);
84 write32(&mtk_spm
->spm_sw_flag_1
, pcm_flags1
);
85 write32(&mtk_spm
->spm_sw_rsv_7
, pcm_flags
);
86 write32(&mtk_spm
->spm_sw_rsv_8
, pcm_flags1
);
89 static void spm_kick_pcm_to_run(const struct pwr_ctrl
*pwrctrl
)
91 /* Waiting for loading SPMFW done*/
92 while (read32(&mtk_spm
->md32pcm_dma0_rlct
) != 0x0)
95 /* Init register to match PCM expectation */
96 write32(&mtk_spm
->spm_bus_protect_mask_b
, SPM_BUS_PROTECT_MASK_B_DEF
);
97 write32(&mtk_spm
->spm_bus_protect2_mask_b
,
98 SPM_BUS_PROTECT2_MASK_B_DEF
);
99 write32(&mtk_spm
->pcm_reg_data_ini
, 0);
101 spm_set_pcm_flags(pwrctrl
);
103 /* Kick PCM to run (only toggle PCM_KICK) */
104 setbits32(&mtk_spm
->pcm_con0
, SPM_REGWR_CFG_KEY
| PCM_CK_EN_LSB
);
107 SET32_BITFIELDS(&mtk_spm
->md32pcm_cfgreg_sw_rstn
,
108 MD32PCM_CFGREG_SW_RSTN_RESET
, 1);
110 /* Waiting for SPM init done */
111 udelay(SPM_INIT_DONE_US
);
114 static void spm_parse_firmware(struct mtk_mcu
*mcu
)
116 size_t file_size
, copy_size
;
120 struct dyna_load_pcm
*pcm
= (struct dyna_load_pcm
*)mcu
->priv
;
121 file_size
= mcu
->run_size
;
126 * u32 binary[firmware_size]
127 * struct pcm_desc descriptor
133 copy_size
= sizeof(firmware_size
);
134 memcpy(&firmware_size
, mcu
->load_buffer
+ offset
, copy_size
);
135 printk(BIOS_DEBUG
, "SPM: binary array size = %#x\n", firmware_size
);
138 offset
= SPMFW_HEADER_SIZE
; /* binary start offset */
139 copy_size
= firmware_size
* sizeof(u32
);
140 assert(offset
< file_size
);
141 pcm
->buf
= (u8
*)(mcu
->load_buffer
+ offset
);
145 assert(offset
< file_size
);
146 copy_size
= sizeof(pcm
->desc
);
147 memcpy(&pcm
->desc
, mcu
->load_buffer
+ offset
, copy_size
);
149 /* Firmware size and total words need to be the same */
150 assert(firmware_size
== pcm
->desc
.total_words
);
154 assert(offset
< file_size
);
155 printk(BIOS_INFO
, "SPM: spmfw (version %.*s)\n",
156 (int)(file_size
- offset
),
157 (u8
*)mcu
->load_buffer
+ offset
);
160 static void reset_spm(struct mtk_mcu
*mcu
)
162 struct dyna_load_pcm
*pcm
= (struct dyna_load_pcm
*)mcu
->priv
;
163 const struct pwr_ctrl
*spm_init_ctrl
= get_pwr_ctrl();
165 spm_parse_firmware(mcu
);
166 spm_reset_and_init_pcm();
167 spm_kick_im_to_fetch(pcm
);
168 spm_init_pcm_register();
169 spm_set_wakeup_event(spm_init_ctrl
);
170 spm_kick_pcm_to_run(spm_init_ctrl
);
173 static struct mtk_mcu spm
= {
174 .firmware_name
= CONFIG_SPM_FIRMWARE
,
178 void spm_code_swapping(void)
182 mask
= read32(&mtk_spm
->spm_wakeup_event_mask
);
183 write32(&mtk_spm
->spm_wakeup_event_mask
,
184 mask
& ~SPM_WAKEUP_EVENT_MASK_BIT0
);
185 write32(&mtk_spm
->spm_cpu_wakeup_event
, 1);
186 write32(&mtk_spm
->spm_cpu_wakeup_event
, 0);
187 write32(&mtk_spm
->spm_wakeup_event_mask
, mask
);
192 struct dyna_load_pcm pcm
;
194 const struct pwr_ctrl
*spm_init_ctrl
= get_pwr_ctrl();
199 spm_set_power_control(spm_init_ctrl
);
200 spm_set_sysclk_settle();
201 spm_extern_initialize();
203 spm
.load_buffer
= _dram_dma
;
204 spm
.buffer_size
= REGION_SIZE(dram_dma
);
205 spm
.priv
= (void *)&pcm
;
207 if (mtk_init_mcu(&spm
)) {
208 printk(BIOS_ERR
, "SPM: %s: failed in mtk_init_mcu\n", __func__
);
212 printk(BIOS_INFO
, "SPM: %s done in %lld msecs, spm pc = %#x\n",
213 __func__
, stopwatch_duration_msecs(&sw
),
214 read32(&mtk_spm
->md32pcm_pc
));