mb/system76/cml-u/dt: Make use of chipset devicetree
[coreboot.git] / src / soc / mediatek / common / spm.c
blobe39f3da56c9b84349be1c60da70783c6c2de1109
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <console/console.h>
5 #include <delay.h>
6 #include <soc/mcu_common.h>
7 #include <soc/spm.h>
8 #include <soc/symbols.h>
9 #include <string.h>
10 #include <timer.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)
23 uintptr_t ptr;
24 u32 dmem_words;
25 u32 pmem_words;
26 u32 total_words;
27 u32 pmem_start;
28 u32 dmem_start;
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);
106 /* Reset md32pcm */
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;
117 int offset;
118 u16 firmware_size;
120 struct dyna_load_pcm *pcm = (struct dyna_load_pcm *)mcu->priv;
121 file_size = mcu->run_size;
124 * spmfw layout:
125 * u16 firmware_size
126 * u32 binary[firmware_size]
127 * struct pcm_desc descriptor
128 * char *version
131 /* Firmware size */
132 offset = 0;
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);
137 /* Binary */
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);
143 /* Descriptor */
144 offset += copy_size;
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);
152 /* Version */
153 offset += copy_size;
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,
175 .reset = reset_spm,
178 void spm_code_swapping(void)
180 u32 mask;
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);
190 int spm_init(void)
192 struct dyna_load_pcm pcm;
193 struct stopwatch sw;
194 const struct pwr_ctrl *spm_init_ctrl = get_pwr_ctrl();
196 stopwatch_init(&sw);
198 spm_register_init();
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__);
209 return -1;
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));
216 return 0;