Files
system76-coreboot/src/soc/mediatek/mt8183/spm.c
Julius Werner 834b3ecd7c cbfs: Simplify load/map API names, remove type arguments
This patch renames cbfs_boot_map_with_leak() and cbfs_boot_load_file()
to cbfs_map() and cbfs_load() respectively. This is supposed to be the
start of a new, better organized CBFS API where the most common
operations have the most simple and straight-forward names. Less
commonly used variants of these operations (e.g. cbfs_ro_load() or
cbfs_region_load()) can be introduced later. It seems unnecessary to
keep carrying around "boot" in the names of most CBFS APIs if the vast
majority of accesses go to the boot CBFS (instead, more unusual
operations should have longer names that describe how they diverge from
the common ones).

cbfs_map() is paired with a new cbfs_unmap() to allow callers to cleanly
reap mappings when desired. A few new cbfs_unmap() calls are added to
generic code where it makes sense, but it seems unnecessary to introduce
this everywhere in platform or architecture specific code where the boot
medium is known to be memory-mapped anyway. In fact, even for
non-memory-mapped platforms, sometimes leaking a mapping to the CBFS
cache is a much cleaner solution than jumping through hoops to provide
some other storage for some long-lived file object, and it shouldn't be
outright forbidden when it makes sense.

Additionally, remove the type arguments from these function signatures.
The goal is to eventually remove type arguments for lookup from the
whole CBFS API. Filenames already uniquely identify CBFS files. The type
field is just informational, and there should be APIs to allow callers
to check it when desired, but it's not clear what we gain from forcing
this as a parameter into every single CBFS access when the vast majority
of the time it provides no additional value and is just clutter.

Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: Ib24325400815a9c3d25f66c61829a24a239bb88e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/39304
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Wim Vervoorn <wvervoorn@eltan.com>
Reviewed-by: Mariusz Szafrański <mariuszx.szafranski@intel.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-12-02 22:13:17 +00:00

338 lines
8.9 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
#include <assert.h>
#include <cbfs.h>
#include <console/console.h>
#include <device/mmio.h>
#include <endian.h>
#include <soc/emi.h>
#include <soc/spm.h>
#include <timer.h>
#define BUF_SIZE (16 * KiB)
static uint8_t spm_bin[BUF_SIZE] __aligned(8);
static int spm_register_init(void)
{
u32 pcm_fsm_sta;
write32(&mtk_spm->poweron_config_set,
SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB | MD_BCLK_CG_EN_LSB);
write32(&mtk_spm->spm_power_on_val1, POWER_ON_VAL1_DEF);
write32(&mtk_spm->pcm_pwr_io_en, 0);
write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
PCM_SW_RESET_LSB);
write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
pcm_fsm_sta = read32(&mtk_spm->pcm_fsm_sta);
if ((pcm_fsm_sta & PCM_FSM_STA_MASK) != PCM_FSM_STA_DEF) {
printk(BIOS_ERR, "PCM reset failed\n");
return -1;
}
write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
EN_IM_SLEEP_DVS_LSB);
write32(&mtk_spm->pcm_con1, SPM_REGWR_CFG_KEY | EVENT_LOCK_EN_LSB |
SPM_SRAM_ISOINT_B_LSB | MIF_APBEN_LSB |
SCP_APB_INTERNAL_EN_LSB);
write32(&mtk_spm->pcm_im_ptr, 0);
write32(&mtk_spm->pcm_im_len, 0);
write32(&mtk_spm->spm_clk_con,
read32(&mtk_spm->spm_clk_con) | SYSCLK1_EN_CTRL |
SPM_LOCK_INFRA_DCM_LSB | EXT_SRCCLKEN_MASK |
CXO32K_REMOVE_EN_MD1_LSB |
CLKSQ1_SEL_CTRL_LSB | SRCLKEN0_EN_LSB | SYSCLK1_SRC_MASK_B);
write32(&mtk_spm->spm_wakeup_event_mask, SPM_WAKEUP_EVENT_MASK_DEF);
write32(&mtk_spm->spm_irq_mask, ISRM_ALL);
write32(&mtk_spm->spm_irq_sta, ISRC_ALL);
write32(&mtk_spm->spm_swint_clr, PCM_SW_INT_ALL);
write32(&mtk_spm->pcm_reg_data_ini,
read32(&mtk_spm->spm_power_on_val1));
write32(&mtk_spm->pcm_pwr_io_en, PCM_RF_SYNC_R7);
write32(&mtk_spm->pcm_pwr_io_en, 0);
write32(&mtk_spm->ddr_en_dbc_len,
MD_DDR_EN_0_DBC_LEN |
MD_DDR_EN_1_DBC_LEN |
CONN_DDR_EN_DBC_LEN);
clrsetbits32(&mtk_spm->spare_ack_mask,
SPARE_ACK_MASK_B_BIT1,
SPARE_ACK_MASK_B_BIT0);
write32(&mtk_spm->sysrom_con, IFR_SRAMROM_ROM_PDN);
write32(&mtk_spm->spm_pc_trace_con,
SPM_PC_TRACE_OFFSET |
SPM_PC_TRACE_HW_EN_LSB);
setbits32(&mtk_spm->spare_src_req_mask, SPARE1_DDREN_MASK_B_LSB);
return 0;
}
static int spm_code_swapping(void)
{
u32 con1;
con1 = read32(&mtk_spm->spm_wakeup_event_mask);
write32(&mtk_spm->spm_wakeup_event_mask,
con1 & ~WAKEUP_EVENT_MASK_B_BIT0);
write32(&mtk_spm->spm_cpu_wakeup_event, 1);
if (!wait_us(SPM_CORE_TIMEOUT,
read32(&mtk_spm->spm_irq_sta) & PCM_IRQ_ROOT_MASK_LSB)) {
printk(BIOS_ERR,
"timeout: r15=%#x, pcmsta=%#x, irqsta=%#x [%d]\n",
read32(&mtk_spm->pcm_reg15_data),
read32(&mtk_spm->pcm_fsm_sta),
read32(&mtk_spm->spm_irq_sta),
SPM_CORE_TIMEOUT);
return -1;
}
write32(&mtk_spm->spm_cpu_wakeup_event, 0);
write32(&mtk_spm->spm_wakeup_event_mask, con1);
return 0;
}
static int spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc)
{
u32 con1, pcm_fsm_sta;
if (read32(&mtk_spm->pcm_reg1_data) == SPM_PCM_REG1_DATA_CHECK &&
read32(&mtk_spm->pcm_reg15_data) != SPM_PCM_REG15_DATA_CHECK) {
if (spm_code_swapping())
return -1;
write32(&mtk_spm->spm_power_on_val0,
read32(&mtk_spm->pcm_reg0_data));
}
write32(&mtk_spm->pcm_pwr_io_en, 0);
clrsetbits32(&mtk_spm->pcm_con1,
PCM_TIMER_EN_LSB,
SPM_REGWR_CFG_KEY);
write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
PCM_SW_RESET_LSB);
write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
pcm_fsm_sta = read32(&mtk_spm->pcm_fsm_sta);
if ((pcm_fsm_sta & PCM_FSM_STA_MASK) != PCM_FSM_STA_DEF) {
printk(BIOS_ERR, "reset pcm(PCM_FSM_STA=%#x)\n",
read32(&mtk_spm->pcm_fsm_sta));
return -1;
}
write32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
EN_IM_SLEEP_DVS_LSB);
con1 = read32(&mtk_spm->pcm_con1) & PCM_WDT_WAKE_MODE_LSB;
write32(&mtk_spm->pcm_con1, con1 | SPM_REGWR_CFG_KEY |
EVENT_LOCK_EN_LSB | SPM_SRAM_ISOINT_B_LSB |
(pcmdesc->replace ? 0 : IM_NONRP_EN_LSB) |
MIF_APBEN_LSB | SCP_APB_INTERNAL_EN_LSB);
return 0;
}
static void spm_load_pcm_code(const struct dyna_load_pcm *pcm)
{
int i;
write32(&mtk_spm->pcm_con1, read32(&mtk_spm->pcm_con1) |
SPM_REGWR_CFG_KEY | IM_SLAVE_LSB);
for (i = 0; i < pcm->desc.size; i++) {
write32(&mtk_spm->pcm_im_host_rw_ptr,
PCM_IM_HOST_EN_LSB | PCM_IM_HOST_W_EN_LSB | i);
write32(&mtk_spm->pcm_im_host_rw_dat,
(u32) *(pcm->buf + i));
}
write32(&mtk_spm->pcm_im_host_rw_ptr, 0);
}
static void spm_check_pcm_code(const struct dyna_load_pcm *pcm)
{
int i;
for (i = 0; i < pcm->desc.size; i++) {
write32(&mtk_spm->pcm_im_host_rw_ptr, PCM_IM_HOST_EN_LSB | i);
if ((read32(&mtk_spm->pcm_im_host_rw_dat)) !=
(u32) *(pcm->buf + i))
spm_load_pcm_code(pcm);
}
write32(&mtk_spm->pcm_im_host_rw_ptr, 0);
}
static void spm_kick_im_to_fetch(const struct dyna_load_pcm *pcm)
{
u32 con0;
spm_load_pcm_code(pcm);
spm_check_pcm_code(pcm);
printk(BIOS_DEBUG, "%s: ptr = %p\n", __func__, pcm->buf);
printk(BIOS_DEBUG, "%s: len = %d\n", __func__, pcm->desc.size);
con0 = read32(&mtk_spm->pcm_con0) & ~(IM_KICK_L_LSB | PCM_KICK_L_LSB);
write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY |
PCM_CK_EN_LSB | IM_KICK_L_LSB);
write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
}
static void spm_init_pcm_register(void)
{
write32(&mtk_spm->pcm_reg_data_ini,
read32(&mtk_spm->spm_power_on_val0));
write32(&mtk_spm->pcm_pwr_io_en, PCM_RF_SYNC_R0);
write32(&mtk_spm->pcm_pwr_io_en, 0);
write32(&mtk_spm->pcm_reg_data_ini,
read32(&mtk_spm->spm_power_on_val1));
write32(&mtk_spm->pcm_pwr_io_en, PCM_RF_SYNC_R7);
write32(&mtk_spm->pcm_pwr_io_en, 0);
}
static void spm_init_event_vector(const struct pcm_desc *pcmdesc)
{
for (int i = 0; i < PCM_EVENT_VECTOR_NUM; i++)
write32(&mtk_spm->pcm_event_vector[i], pcmdesc->vector[i]);
}
static const char * const dyna_load_pcm_path[] = {
[DYNA_LOAD_PCM_SUSPEND_LP4_3733] = "pcm_allinone_lp4_3733.bin",
[DYNA_LOAD_PCM_SUSPEND_LP4_3200] = "pcm_allinone_lp4_3200.bin",
};
static int spm_load_firmware(enum dyna_load_pcm_index index,
struct dyna_load_pcm *pcm)
{
/*
* Layout:
* u16 firmware_size
* u32 binary[firmware_size]
* struct pcm_desc descriptor
* char *version
*/
u16 firmware_size;
int copy_size;
const char *file_name = dyna_load_pcm_path[index];
struct stopwatch sw;
stopwatch_init(&sw);
size_t file_size = cbfs_load(file_name, spm_bin, sizeof(spm_bin));
if (file_size == 0) {
printk(BIOS_ERR, "SPM binary %s not found\n", file_name);
return -1;
}
int offset = 0;
/* firmware size */
copy_size = sizeof(firmware_size);
memcpy(&firmware_size, spm_bin + offset, copy_size);
printk(BIOS_DEBUG, "SPM: binary array size = %d\n", firmware_size);
offset += copy_size;
/* binary */
assert(offset < file_size);
copy_size = firmware_size * 4;
pcm->buf = (u32 *)(spm_bin + offset);
offset += copy_size;
/* descriptor */
assert(offset < file_size);
copy_size = sizeof(struct pcm_desc);
memcpy((void *)&(pcm->desc.size), spm_bin + offset, copy_size);
offset += copy_size;
/* version */
/* The terminating character should be contained in the spm binary */
assert(spm_bin[file_size - 1] == '\0');
assert(offset < file_size);
printk(BIOS_DEBUG, "SPM: version = %s\n", spm_bin + offset);
printk(BIOS_INFO, "SPM binary loaded in %ld msecs\n",
stopwatch_duration_msecs(&sw));
return 0;
}
static void spm_kick_pcm_to_run(void)
{
uint32_t con0;
write32(&mtk_spm->spm_mas_pause_mask_b, SPM_MAS_PAUSE_MASK_B_VAL);
write32(&mtk_spm->spm_mas_pause2_mask_b, SPM_MAS_PAUSE2_MASK_B_VAL);
write32(&mtk_spm->pcm_reg_data_ini, 0);
write32(&mtk_spm->pcm_pwr_io_en, PCM_PWRIO_EN_R0 | PCM_PWRIO_EN_R7);
printk(BIOS_DEBUG, "SPM: %s\n", __func__);
/* check IM ready */
while ((read32(&mtk_spm->pcm_fsm_sta) & IM_STATE_MASK) != IM_STATE)
;
/* kick PCM to run, and toggle PCM_KICK */
con0 = read32(&mtk_spm->pcm_con0) & ~(IM_KICK_L_LSB | PCM_KICK_L_LSB);
write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB |
PCM_KICK_L_LSB);
write32(&mtk_spm->pcm_con0, con0 | SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
printk(BIOS_DEBUG, "SPM: %s done\n", __func__);
}
int spm_init(void)
{
struct pcm_desc *pcmdesc;
enum dyna_load_pcm_index index;
struct stopwatch sw;
stopwatch_init(&sw);
if (CONFIG(MT8183_DRAM_EMCP))
index = DYNA_LOAD_PCM_SUSPEND_LP4_3733;
else
index = DYNA_LOAD_PCM_SUSPEND_LP4_3200;
printk(BIOS_DEBUG, "SPM: pcm index = %d\n", index);
struct dyna_load_pcm pcm;
if (spm_load_firmware(index, &pcm)) {
printk(BIOS_ERR, "SPM: firmware is not ready\n");
printk(BIOS_ERR, "SPM: check dram type and firmware version\n");
return -1;
}
pcmdesc = &pcm.desc;
if (spm_register_init())
return -1;
if (spm_reset_and_init_pcm(pcmdesc))
return -1;
spm_kick_im_to_fetch(&pcm);
spm_init_pcm_register();
spm_init_event_vector(pcmdesc);
spm_kick_pcm_to_run();
printk(BIOS_INFO, "SPM: %s done in %ld msecs\n", __func__,
stopwatch_duration_msecs(&sw));
return 0;
}