soc/intel/xeon_sp: Allow OS to control LTR and AER
[coreboot2.git] / src / soc / mediatek / common / spm.c
blob65372f9375aff0770e813e4bea5e249fb1041b58
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 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;
77 int offset;
78 u16 firmware_size;
80 struct dyna_load_pcm *pcm = (struct dyna_load_pcm *)mcu->priv;
81 file_size = mcu->run_size;
84 * spmfw layout:
85 * u16 firmware_size
86 * u32 binary[firmware_size]
87 * struct pcm_desc descriptor
88 * char *version
91 /* Firmware size */
92 offset = 0;
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);
97 /* Binary */
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);
103 /* Descriptor */
104 offset += copy_size;
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);
112 /* Version */
113 offset += copy_size;
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,
135 .reset = reset_spm,
138 void spm_code_swapping(void)
140 u32 mask;
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);
150 int spm_init(void)
152 struct dyna_load_pcm pcm;
153 struct stopwatch sw;
154 const struct pwr_ctrl *spm_init_ctrl = get_pwr_ctrl();
156 stopwatch_init(&sw);
158 spm_register_init();
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__);
169 return -1;
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));
176 return 0;