coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
spm.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <cbfs.h>
5 #include <console/console.h>
6 #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)
13 static uint8_t spm_bin[BUF_SIZE] __aligned(8);
14 
15 static int spm_register_init(void)
16 {
17  u32 pcm_fsm_sta;
18 
21 
24 
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 
43 
49 
51 
55 
60 
65 
69 
74 
76 
77  return 0;
78 }
79 
80 static int spm_code_swapping(void)
81 {
82  u32 con1;
83 
85 
87  con1 & ~WAKEUP_EVENT_MASK_B_BIT0);
89 
93  "timeout: r15=%#x, pcmsta=%#x, irqsta=%#x [%d]\n",
98  return -1;
99  }
100 
103  return 0;
104 }
105 
106 static int spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc)
107 {
108  u32 con1, pcm_fsm_sta;
109 
112  if (spm_code_swapping())
113  return -1;
116  }
117 
119 
123 
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",
133  return -1;
134  }
135 
138 
142  (pcmdesc->replace ? 0 : IM_NONRP_EN_LSB) |
144 
145  return 0;
146 }
147 
148 static void spm_load_pcm_code(const struct dyna_load_pcm *pcm)
149 {
150  int i;
151 
154 
155  for (i = 0; i < pcm->desc.size; i++) {
159  (u32) *(pcm->buf + i));
160  }
162 }
163 
164 static 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++) {
170  if ((read32(&mtk_spm->pcm_im_host_rw_dat)) !=
171  (u32) *(pcm->buf + i))
172  spm_load_pcm_code(pcm);
173  }
175 }
176 
177 static 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 
191 }
192 
193 static void spm_init_pcm_register(void)
194 {
199 
204 }
205 
206 static 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 
212 static 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 
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 
234  size_t file_size = cbfs_load(file_name, spm_bin, sizeof(spm_bin));
235 
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 */
262  /* The terminating character should be contained in the spm binary */
263  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",
269 
270  return 0;
271 }
272 
273 static void spm_kick_pcm_to_run(void)
274 {
275  uint32_t con0;
276 
280 
282 
283  printk(BIOS_DEBUG, "SPM: %s\n", __func__);
284 
285  /* check IM ready */
287  ;
288 
289  /* kick PCM to run, and toggle PCM_KICK */
294 
295  printk(BIOS_DEBUG, "SPM: %s done\n", __func__);
296 }
297 
298 int 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))
308  else
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);
330  spm_init_event_vector(pcmdesc);
332 
333  printk(BIOS_INFO, "SPM: %s done in %ld msecs\n", __func__,
335 
336  return 0;
337 }
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define assert(statement)
Definition: assert.h:74
static size_t cbfs_load(const char *name, void *buf, size_t size)
Definition: cbfs.h:282
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
static size_t offset
Definition: flashconsole.c:16
#define setbits32(addr, set)
Definition: mmio.h:21
#define clrsetbits32(addr, clear, set)
Definition: mmio.h:16
#define wait_us(timeout_us, condition)
Definition: timer.h:198
static void stopwatch_init(struct stopwatch *sw)
Definition: timer.h:117
static long stopwatch_duration_msecs(struct stopwatch *sw)
Definition: timer.h:182
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static struct mtk_spm_regs *const mtk_spm
Definition: spm.h:154
#define SPM_PC_TRACE_HW_EN_LSB
Definition: spm.h:65
#define SYSCLK1_SRC_MASK_B
Definition: spm.h:90
#define CONN_DDR_EN_DBC_LEN
Definition: spm.h:74
#define PCM_TIMER_EN_LSB
Definition: spm.h:42
#define PCM_FSM_STA_DEF
Definition: spm.h:80
#define MD_DDR_EN_1_DBC_LEN
Definition: spm.h:79
#define CXO32K_REMOVE_EN_MD1_LSB
Definition: spm.h:25
#define PCM_CK_EN_LSB
Definition: spm.h:32
#define SPM_MAS_PAUSE_MASK_B_VAL
Definition: spm.h:84
#define SRCLKEN0_EN_LSB
Definition: spm.h:27
#define IFR_SRAMROM_ROM_PDN
Definition: spm.h:75
#define SPM_LOCK_INFRA_DCM_LSB
Definition: spm.h:23
#define IM_NONRP_EN_LSB
Definition: spm.h:43
#define SCP_APB_INTERNAL_EN_LSB
Definition: spm.h:51
#define EVENT_LOCK_EN_LSB
Definition: spm.h:49
#define PCM_EVENT_VECTOR_NUM
Definition: spm.h:129
#define PCM_IM_HOST_W_EN_LSB
Definition: spm.h:17
dyna_load_pcm_index
Definition: spm.h:562
@ DYNA_LOAD_PCM_SUSPEND_LP4_3733
Definition: spm.h:563
@ DYNA_LOAD_PCM_SUSPEND_LP4_3200
Definition: spm.h:564
#define PCM_PWRIO_EN_R7
Definition: spm.h:112
#define SPARE_ACK_MASK_B_BIT0
Definition: spm.h:68
#define MD_DDR_EN_0_DBC_LEN
Definition: spm.h:78
#define IM_STATE
Definition: spm.h:76
#define SPM_PCM_REG1_DATA_CHECK
Definition: spm.h:86
#define SPM_SRAM_ISOINT_B_LSB
Definition: spm.h:48
#define EN_IM_SLEEP_DVS_LSB
Definition: spm.h:33
#define SPM_WAKEUP_EVENT_MASK_DEF
Definition: spm.h:88
#define CLKSQ1_SEL_CTRL_LSB
Definition: spm.h:26
#define SPM_MAS_PAUSE2_MASK_B_VAL
Definition: spm.h:85
#define PCM_FSM_STA_MASK
Definition: spm.h:81
#define MIF_APBEN_LSB
Definition: spm.h:40
#define SPARE1_DDREN_MASK_B_LSB
Definition: spm.h:60
#define IM_KICK_L_LSB
Definition: spm.h:31
#define EXT_SRCCLKEN_MASK
Definition: spm.h:24
#define ISRM_ALL
Definition: spm.h:100
#define SPM_PCM_REG15_DATA_CHECK
Definition: spm.h:87
#define PCM_SW_RESET_LSB
Definition: spm.h:35
#define MD_BCLK_CG_EN_LSB
Definition: spm.h:16
#define PCM_SW_INT_ALL
Definition: spm.h:118
#define BCLK_CG_EN_LSB
Definition: spm.h:15
#define SYSCLK1_EN_CTRL
Definition: spm.h:89
#define PCM_IRQ_ROOT_MASK_LSB
Definition: spm.h:54
#define SPM_REGWR_CFG_KEY
Definition: spm.h:12
#define PCM_WDT_WAKE_MODE_LSB
Definition: spm.h:46
#define PCM_RF_SYNC_R0
Definition: spm.h:113
#define PCM_RF_SYNC_R7
Definition: spm.h:115
#define WAKEUP_EVENT_MASK_B_BIT0
Definition: spm.h:57
#define PCM_PWRIO_EN_R0
Definition: spm.h:111
#define PCM_KICK_L_LSB
Definition: spm.h:30
#define PCM_IM_HOST_EN_LSB
Definition: spm.h:18
#define POWER_ON_VAL1_DEF
Definition: spm.h:82
#define IM_STATE_MASK
Definition: spm.h:77
#define IM_SLAVE_LSB
Definition: spm.h:38
#define SPM_CORE_TIMEOUT
Definition: spm.h:83
#define ISRC_ALL
Definition: spm.h:108
#define SPARE_ACK_MASK_B_BIT1
Definition: spm.h:69
#define SPM_PC_TRACE_OFFSET
Definition: spm.h:64
static int spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc)
Definition: spm.c:106
static void spm_kick_pcm_to_run(void)
Definition: spm.c:273
static int spm_register_init(void)
Definition: spm.c:15
static void spm_load_pcm_code(const struct dyna_load_pcm *pcm)
Definition: spm.c:148
static int spm_code_swapping(void)
Definition: spm.c:80
int spm_init(void)
Definition: spm.c:298
#define BUF_SIZE
Definition: spm.c:12
static int spm_load_firmware(enum dyna_load_pcm_index index, struct dyna_load_pcm *pcm)
Definition: spm.c:217
static void spm_kick_im_to_fetch(const struct dyna_load_pcm *pcm)
Definition: spm.c:177
static void spm_init_pcm_register(void)
Definition: spm.c:193
static const char *const dyna_load_pcm_path[]
Definition: spm.c:212
static uint8_t spm_bin[BUF_SIZE] __aligned(8)
static void spm_init_event_vector(const struct pcm_desc *pcmdesc)
Definition: spm.c:206
static void spm_check_pcm_code(const struct dyna_load_pcm *pcm)
Definition: spm.c:164
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48
unsigned char uint8_t
Definition: stdint.h:8
u32 * buf
Definition: spm.h:578
struct pcm_desc desc
Definition: spm.h:579
u32 spm_cpu_wakeup_event
Definition: spm.h:161
u32 pcm_event_vector[PCM_EVENT_VECTOR_NUM]
Definition: spm.h:148
u32 spm_pc_trace_con
Definition: spm.h:520
u32 pcm_con1
Definition: spm.h:71
u32 pcm_im_ptr
Definition: spm.h:72
u32 pcm_pwr_io_en
Definition: spm.h:82
u32 pcm_im_host_rw_ptr
Definition: spm.h:89
u32 spm_power_on_val1
Definition: spm.h:134
u32 spm_irq_mask
Definition: spm.h:162
u32 spare_ack_mask
Definition: spm.h:453
u32 spm_swint_clr
Definition: spm.h:154
u32 pcm_im_len
Definition: spm.h:73
u32 pcm_reg_data_ini
Definition: spm.h:74
u32 spm_irq_sta
Definition: spm.h:199
u32 spm_mas_pause2_mask_b
Definition: spm.h:305
u32 pcm_im_host_rw_dat
Definition: spm.h:90
u32 spm_clk_con
Definition: spm.h:135
u32 spare_src_req_mask
Definition: spm.h:448
u32 spm_power_on_val0
Definition: spm.h:133
u32 ddr_en_dbc_len
Definition: spm.h:171
u32 spm_mas_pause_mask_b
Definition: spm.h:304
u32 pcm_fsm_sta
Definition: spm.h:88
u32 sysrom_con
Definition: spm.h:286
u32 spm_wakeup_event_mask
Definition: spm.h:166
u32 pcm_reg15_data
Definition: spm.h:192
u32 poweron_config_set
Definition: spm.h:24
u32 pcm_reg1_data
Definition: spm.h:178
u32 pcm_con0
Definition: spm.h:70
u32 pcm_reg0_data
Definition: spm.h:177
Definition: spm.h:568
u32 vector[PCM_EVENT_VECTOR_NUM]
Definition: spm.h:574
u8 replace
Definition: spm.h:571
u16 size
Definition: spm.h:569