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 void spm_set_pcm_flags(const struct pwr_ctrl
*pwrctrl
)
56 u32 pcm_flags
= pwrctrl
->pcm_flags
, pcm_flags1
= pwrctrl
->pcm_flags1
;
58 /* Set PCM flags and data */
59 if (pwrctrl
->pcm_flags_cust_clr
!= 0)
60 pcm_flags
&= ~pwrctrl
->pcm_flags_cust_clr
;
61 if (pwrctrl
->pcm_flags_cust_set
!= 0)
62 pcm_flags
|= pwrctrl
->pcm_flags_cust_set
;
63 if (pwrctrl
->pcm_flags1_cust_clr
!= 0)
64 pcm_flags1
&= ~pwrctrl
->pcm_flags1_cust_clr
;
65 if (pwrctrl
->pcm_flags1_cust_set
!= 0)
66 pcm_flags1
|= pwrctrl
->pcm_flags1_cust_set
;
68 write32(&mtk_spm
->spm_sw_flag_0
, pcm_flags
);
69 write32(&mtk_spm
->spm_sw_flag_1
, pcm_flags1
);
70 write32(&mtk_spm
->spm_sw_rsv
[7], pcm_flags
);
71 write32(&mtk_spm
->spm_sw_rsv
[8], pcm_flags1
);
74 static void spm_parse_firmware(struct mtk_mcu
*mcu
)
76 size_t file_size
, copy_size
;
80 struct dyna_load_pcm
*pcm
= (struct dyna_load_pcm
*)mcu
->priv
;
81 file_size
= mcu
->run_size
;
86 * u32 binary[firmware_size]
87 * struct pcm_desc descriptor
93 copy_size
= sizeof(firmware_size
);
94 memcpy(&firmware_size
, mcu
->load_buffer
+ offset
, copy_size
);
95 printk(BIOS_DEBUG
, "SPM: binary array size = %#x\n", firmware_size
);
98 offset
= SPMFW_HEADER_SIZE
; /* binary start offset */
99 copy_size
= firmware_size
* sizeof(u32
);
100 assert(offset
< file_size
);
101 pcm
->buf
= (u8
*)(mcu
->load_buffer
+ offset
);
105 assert(offset
< file_size
);
106 copy_size
= sizeof(pcm
->desc
);
107 memcpy(&pcm
->desc
, mcu
->load_buffer
+ offset
, copy_size
);
109 /* Firmware size and total words need to be the same */
110 assert(firmware_size
== pcm
->desc
.total_words
);
114 assert(offset
< file_size
);
115 printk(BIOS_INFO
, "SPM: spmfw (version %.*s)\n",
116 (int)(file_size
- offset
),
117 (u8
*)mcu
->load_buffer
+ offset
);
120 static void reset_spm(struct mtk_mcu
*mcu
)
122 struct dyna_load_pcm
*pcm
= (struct dyna_load_pcm
*)mcu
->priv
;
123 const struct pwr_ctrl
*spm_init_ctrl
= get_pwr_ctrl();
125 spm_parse_firmware(mcu
);
126 spm_reset_and_init_pcm();
127 spm_kick_im_to_fetch(pcm
);
128 spm_init_pcm_register();
129 spm_set_wakeup_event(spm_init_ctrl
);
130 spm_kick_pcm_to_run(spm_init_ctrl
);
133 static struct mtk_mcu spm
= {
134 .firmware_name
= CONFIG_SPM_FIRMWARE
,
138 void spm_code_swapping(void)
142 mask
= read32(&mtk_spm
->spm_wakeup_event_mask
);
143 write32(&mtk_spm
->spm_wakeup_event_mask
,
144 mask
& ~SPM_WAKEUP_EVENT_MASK_BIT0
);
145 write32(&mtk_spm
->spm_cpu_wakeup_event
, 1);
146 write32(&mtk_spm
->spm_cpu_wakeup_event
, 0);
147 write32(&mtk_spm
->spm_wakeup_event_mask
, mask
);
152 struct dyna_load_pcm pcm
;
154 const struct pwr_ctrl
*spm_init_ctrl
= get_pwr_ctrl();
159 spm_set_power_control(spm_init_ctrl
);
160 spm_set_sysclk_settle();
161 spm_extern_initialize();
163 spm
.load_buffer
= _dram_dma
;
164 spm
.buffer_size
= REGION_SIZE(dram_dma
);
165 spm
.priv
= (void *)&pcm
;
167 if (mtk_init_mcu(&spm
)) {
168 printk(BIOS_ERR
, "SPM: %s: failed in mtk_init_mcu\n", __func__
);
172 printk(BIOS_INFO
, "SPM: %s done in %lld msecs, spm pc = %#x\n",
173 __func__
, stopwatch_duration_msecs(&sw
),
174 read32(&mtk_spm
->md32pcm_pc
));