soc/mediatek/mt8192: add spmfw loader

This patch adds support for loading spm firmware from cbfs to spm sram.
Spm needs its own firmware to enable spm suspend/resume function which
turns off several resources such as DRAM/mainpll/26M clk when linux
system suspend.

BUG=b:159079649
TEST=suspend with command `powerd_dbus_suspend` and
     wake up the DUT by powerkey

Signed-off-by: Roger Lu <roger.lu@mediatek.com>
Change-Id: I6478b98f426d2f3e0ee919d37d21d909ae8a6371
Reviewed-on: https://review.coreboot.org/c/coreboot/+/46389
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
This commit is contained in:
Roger Lu 2020-07-10 15:29:31 +08:00 committed by Hung-Te Lin
parent eb69dd60ef
commit a5f472bf57
5 changed files with 1134 additions and 31 deletions

View File

@ -6,6 +6,7 @@
#include <device/mmio.h> #include <device/mmio.h>
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/regulator.h> #include <soc/regulator.h>
#include <soc/spm.h>
#include <soc/usb.h> #include <soc/usb.h>
#include "gpio.h" #include "gpio.h"
@ -107,6 +108,9 @@ static void mainboard_init(struct device *dev)
setup_usb_host(); setup_usb_host();
register_reset_to_bl31(); register_reset_to_bl31();
if (spm_init())
printk(BIOS_ERR, "spm init fail, system suspend may stuck\n");
} }
static void mainboard_enable(struct device *dev) static void mainboard_enable(struct device *dev)

View File

@ -45,4 +45,10 @@ config MEMORY_TEST
This option enables memory basic compare test to verify the DRAM read This option enables memory basic compare test to verify the DRAM read
or write is as expected. or write is as expected.
config SPM_FIRMWARE
string
default "spm_firmware.bin"
help
The file name of the MediaTek SPM firmware.
endif endif

View File

@ -43,12 +43,23 @@ ramstage-y += ../common/mcu.c
ramstage-y += ../common/mmu_operations.c mmu_operations.c ramstage-y += ../common/mmu_operations.c mmu_operations.c
ramstage-y += ../common/mtcmos.c mtcmos.c ramstage-y += ../common/mtcmos.c mtcmos.c
ramstage-y += soc.c ramstage-y += soc.c
ramstage-y += spm.c
ramstage-y += ../common/timer.c ramstage-y += ../common/timer.c
ramstage-y += ../common/uart.c ramstage-y += ../common/uart.c
ramstage-y += ../common/usb.c usb.c ramstage-y += ../common/usb.c usb.c
MT8192_BLOB_DIR := 3rdparty/blobs/soc/mediatek/mt8192 MT8192_BLOB_DIR := 3rdparty/blobs/soc/mediatek/mt8192
mcu-firmware-files := \
$(CONFIG_SPM_FIRMWARE)
$(foreach fw, $(call strip_quotes,$(mcu-firmware-files)), \
$(eval $(fw)-file := $(MT8192_BLOB_DIR)/$(fw)) \
$(eval $(fw)-type := raw) \
$(eval $(fw)-compression := $(CBFS_COMPRESS_FLAG)) \
$(if $(wildcard $($(fw)-file)), $(eval cbfs-files-y += $(fw)), ) \
)
DRAM_CBFS := $(CONFIG_CBFS_PREFIX)/dram DRAM_CBFS := $(CONFIG_CBFS_PREFIX)/dram
$(DRAM_CBFS)-file := $(MT8192_BLOB_DIR)/dram.elf $(DRAM_CBFS)-file := $(MT8192_BLOB_DIR)/dram.elf
$(DRAM_CBFS)-type := stage $(DRAM_CBFS)-type := stage

View File

@ -4,10 +4,309 @@
#define SOC_MEDIATEK_MT8192_SPM_H #define SOC_MEDIATEK_MT8192_SPM_H
#include <soc/addressmap.h> #include <soc/addressmap.h>
#include <stdint.h>
#include <types.h> #include <types.h>
/* SPM READ/WRITE CFG */ /* SPM READ/WRITE CFG */
#define SPM_PROJECT_CODE 0xb16 #define SPM_PROJECT_CODE 0xb16
#define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16)
/* POWERON_CONFIG_EN (0x10006000+0x000) */
#define BCLK_CG_EN_LSB (1U << 0) /* 1b */
/* SPM_CLK_CON (0x10006000+0x00C) */
#define REG_SYSCLK1_SRC_MD2_SRCCLKENA (1U << 28) /* 1b */
/* PCM_CON0 (0x10006000+0x018) */
#define PCM_CK_EN_LSB (1U << 2) /* 1b */
#define PCM_SW_RESET_LSB (1U << 15) /* 1b */
/* PCM_CON1 (0x10006000+0x01C) */
#define RG_IM_SLAVE_LSB (1U << 0) /* 1b */
#define RG_AHBMIF_APBEN_LSB (1U << 3) /* 1b */
#define RG_PCM_TIMER_EN_LSB (1U << 5) /* 1b */
#define SPM_EVENT_COUNTER_CLR_LSB (1U << 6) /* 1b */
#define RG_PCM_WDT_WAKE_LSB (1U << 9) /* 1b */
#define REG_SPM_SRAM_ISOINT_B_LSB (1U << 11) /* 1b */
#define REG_EVENT_LOCK_EN_LSB (1U << 12) /* 1b */
#define REG_MD32_APB_INTERNAL_EN_LSB (1U << 14) /* 1b */
/* SPM_WAKEUP_EVENT_MASK (0x10006000+0x0D0) */
#define SPM_WAKEUP_EVENT_MASK_BIT0 (1U << 0) /* 1b */
#define SPM_WAKEUP_EVENT_MASK_CSYSPWREQ_B (1U << 24) /* 1b */
/* DDR_EN_DBC_CON1 (0x10006000+0x0EC) */
#define REG_ALL_DDR_EN_DBC_EN_LSB (1U << 0) /* 1b */
/* SPM_DVFS_MISC (0x10006000+0x4AC) */
#define SPM_DVFS_FORCE_ENABLE_LSB (1U << 2) /* 1b */
#define SPM_DVFSRC_ENABLE_LSB (1U << 4) /* 1b */
/* SPM_SW_FLAG_0 (0x10006000+0x600) */
#define SPM_FLAG_DISABLE_VCORE_DVS (1U << 3) /* 1b */
#define SPM_FLAG_DISABLE_VCORE_DFS (1U << 4) /* 1b */
#define SPM_FLAG_RUN_COMMON_SCENARIO (1U << 10) /* 1b */
/* SYS_TIMER_CON (0x10006000+0x98C) */
#define SYS_TIMER_START_EN_LSB (1U << 0) /* 1b */
/* MD32PCM_CFGREG_SW_RSTN (0x10006000+0xA00) */
#define MD32PCM_CFGREG_SW_RSTN_RESET (1U << 0) /* 1b */
/**************************************
* Config and Parameter
**************************************/
#define POWER_ON_VAL1_DEF 0x80015860
#define SPM_WAKEUP_EVENT_MASK_DEF 0xefffffff
#define SPM_ACK_CHK_3_SEL_HW_S1 0x00350098
#define SPM_ACK_CHK_3_HW_S1_CNT 0x1
#define SPM_ACK_CHK_3_CON_HW_MODE_TRIG 0x800
#define SPM_ACK_CHK_3_CON_EN 0x110
#define SPM_ACK_CHK_3_CON_CLR_ALL 0x2
#define SPM_BUS_PROTECT_MASK_B_DEF 0xffffffff
#define SPM_BUS_PROTECT2_MASK_B_DEF 0xffffffff
#define MD32PCM_DMA0_CON_VAL 0x0003820e
#define MD32PCM_DMA0_START_VAL 0x00008000
#define MD32PCM_CFGREG_SW_RSTN_RUN 0x1
#define SPM_DVFS_LEVEL_DEF 0x00000001
#define SPM_DVS_DFS_LEVEL_DEF 0x00010001
#define SPM_RESOURCE_ACK_CON0_DEF 0x00000000
#define SPM_RESOURCE_ACK_CON1_DEF 0x00000000
#define SPM_RESOURCE_ACK_CON2_DEF 0xcccc4e4e
#define SPM_RESOURCE_ACK_CON3_DEF 0x00000000
#define ARMPLL_CLK_SEL_DEF 0x3ff
#define DDR_EN_DBC_CON0_DEF 0x154
#define SPM_SYSCLK_SETTLE 0x60fe
#define SPM_INIT_DONE_US 20
#define PCM_WDT_TIMEOUT (30 * 32768)
#define PCM_TIMER_MAX (0xffffffff - PCM_WDT_TIMEOUT)
/**************************************
* Define and Declare
**************************************/
/* SPM_IRQ_MASK */
#define ISRM_TWAM (1U << 2)
#define ISRM_PCM_RETURN (1U << 3)
#define ISRM_RET_IRQ_AUX 0x3fe00
#define ISRM_ALL_EXC_TWAM (ISRM_RET_IRQ_AUX)
#define ISRM_ALL (ISRM_ALL_EXC_TWAM | ISRM_TWAM)
/* SPM_IRQ_STA */
#define ISRS_TWAM (1U << 2)
#define ISRS_PCM_RETURN (1U << 3)
#define ISRC_TWAM ISRS_TWAM
#define ISRC_ALL_EXC_TWAM ISRS_PCM_RETURN
#define ISRC_ALL (ISRC_ALL_EXC_TWAM | ISRC_TWAM)
/* PCM_PWR_IO_EN */
#define PCM_PWRIO_EN_R0 (1U << 0)
#define PCM_PWRIO_EN_R7 (1U << 7)
#define PCM_RF_SYNC_R0 (1U << 16)
#define PCM_RF_SYNC_R6 (1U << 22)
#define PCM_RF_SYNC_R7 (1U << 23)
/* SPM_SWINT */
#define PCM_SW_INT_ALL 0x3ff
struct pwr_ctrl {
u32 pcm_flags;
u32 pcm_flags_cust;
u32 pcm_flags_cust_set;
u32 pcm_flags_cust_clr;
u32 pcm_flags1;
u32 pcm_flags1_cust;
u32 pcm_flags1_cust_set;
u32 pcm_flags1_cust_clr;
u32 timer_val;
u32 timer_val_cust;
u32 timer_val_ramp_en;
u32 timer_val_ramp_en_sec;
u32 wake_src;
u32 wake_src_cust;
u32 wakelock_timer_val;
u8 wdt_disable;
/* Auto-gen Start */
/* SPM_CLK_CON */
u8 reg_srcclken0_ctl;
u8 reg_srcclken1_ctl;
u8 reg_spm_lock_infra_dcm;
u8 reg_srcclken_mask;
u8 reg_md1_c32rm_en;
u8 reg_md2_c32rm_en;
u8 reg_clksq0_sel_ctrl;
u8 reg_clksq1_sel_ctrl;
u8 reg_srcclken0_en;
u8 reg_srcclken1_en;
u32 reg_sysclk0_src_mask_b;
u32 reg_sysclk1_src_mask_b;
/* SPM_AP_STANDBY_CON */
u8 reg_wfi_op;
u8 reg_wfi_type;
u8 reg_mp0_cputop_idle_mask;
u8 reg_mp1_cputop_idle_mask;
u8 reg_mcusys_idle_mask;
u8 reg_md_apsrc_1_sel;
u8 reg_md_apsrc_0_sel;
u8 reg_conn_apsrc_sel;
/* SPM_SRC6_MASK */
u8 reg_dpmaif_srcclkena_mask_b;
u8 reg_dpmaif_infra_req_mask_b;
u8 reg_dpmaif_apsrc_req_mask_b;
u8 reg_dpmaif_vrf18_req_mask_b;
u8 reg_dpmaif_ddr_en_mask_b;
/* SPM_SRC_REQ */
u8 reg_spm_apsrc_req;
u8 reg_spm_f26m_req;
u8 reg_spm_infra_req;
u8 reg_spm_vrf18_req;
u8 reg_spm_ddr_en_req;
u8 reg_spm_dvfs_req;
u8 reg_spm_sw_mailbox_req;
u8 reg_spm_sspm_mailbox_req;
u8 reg_spm_adsp_mailbox_req;
u8 reg_spm_scp_mailbox_req;
/* SPM_SRC_MASK */
u8 reg_md_srcclkena_0_mask_b;
u8 reg_md_srcclkena2infra_req_0_mask_b;
u8 reg_md_apsrc2infra_req_0_mask_b;
u8 reg_md_apsrc_req_0_mask_b;
u8 reg_md_vrf18_req_0_mask_b;
u8 reg_md_ddr_en_0_mask_b;
u8 reg_md_srcclkena_1_mask_b;
u8 reg_md_srcclkena2infra_req_1_mask_b;
u8 reg_md_apsrc2infra_req_1_mask_b;
u8 reg_md_apsrc_req_1_mask_b;
u8 reg_md_vrf18_req_1_mask_b;
u8 reg_md_ddr_en_1_mask_b;
u8 reg_conn_srcclkena_mask_b;
u8 reg_conn_srcclkenb_mask_b;
u8 reg_conn_infra_req_mask_b;
u8 reg_conn_apsrc_req_mask_b;
u8 reg_conn_vrf18_req_mask_b;
u8 reg_conn_ddr_en_mask_b;
u8 reg_conn_vfe28_mask_b;
u8 reg_srcclkeni0_srcclkena_mask_b;
u8 reg_srcclkeni0_infra_req_mask_b;
u8 reg_srcclkeni1_srcclkena_mask_b;
u8 reg_srcclkeni1_infra_req_mask_b;
u8 reg_srcclkeni2_srcclkena_mask_b;
u8 reg_srcclkeni2_infra_req_mask_b;
u8 reg_infrasys_apsrc_req_mask_b;
u8 reg_infrasys_ddr_en_mask_b;
u8 reg_md32_srcclkena_mask_b;
u8 reg_md32_infra_req_mask_b;
u8 reg_md32_apsrc_req_mask_b;
u8 reg_md32_vrf18_req_mask_b;
u8 reg_md32_ddr_en_mask_b;
/* SPM_SRC2_MASK */
u8 reg_scp_srcclkena_mask_b;
u8 reg_scp_infra_req_mask_b;
u8 reg_scp_apsrc_req_mask_b;
u8 reg_scp_vrf18_req_mask_b;
u8 reg_scp_ddr_en_mask_b;
u8 reg_audio_dsp_srcclkena_mask_b;
u8 reg_audio_dsp_infra_req_mask_b;
u8 reg_audio_dsp_apsrc_req_mask_b;
u8 reg_audio_dsp_vrf18_req_mask_b;
u8 reg_audio_dsp_ddr_en_mask_b;
u8 reg_ufs_srcclkena_mask_b;
u8 reg_ufs_infra_req_mask_b;
u8 reg_ufs_apsrc_req_mask_b;
u8 reg_ufs_vrf18_req_mask_b;
u8 reg_ufs_ddr_en_mask_b;
u8 reg_disp0_apsrc_req_mask_b;
u8 reg_disp0_ddr_en_mask_b;
u8 reg_disp1_apsrc_req_mask_b;
u8 reg_disp1_ddr_en_mask_b;
u8 reg_gce_infra_req_mask_b;
u8 reg_gce_apsrc_req_mask_b;
u8 reg_gce_vrf18_req_mask_b;
u8 reg_gce_ddr_en_mask_b;
u8 reg_apu_srcclkena_mask_b;
u8 reg_apu_infra_req_mask_b;
u8 reg_apu_apsrc_req_mask_b;
u8 reg_apu_vrf18_req_mask_b;
u8 reg_apu_ddr_en_mask_b;
u8 reg_cg_check_srcclkena_mask_b;
u8 reg_cg_check_apsrc_req_mask_b;
u8 reg_cg_check_vrf18_req_mask_b;
u8 reg_cg_check_ddr_en_mask_b;
/* SPM_SRC3_MASK */
u8 reg_dvfsrc_event_trigger_mask_b;
u8 reg_sw2spm_int0_mask_b;
u8 reg_sw2spm_int1_mask_b;
u8 reg_sw2spm_int2_mask_b;
u8 reg_sw2spm_int3_mask_b;
u8 reg_sc_adsp2spm_wakeup_mask_b;
u8 reg_sc_sspm2spm_wakeup_mask_b;
u8 reg_sc_scp2spm_wakeup_mask_b;
u8 reg_csyspwrreq_mask;
u8 reg_spm_srcclkena_reserved_mask_b;
u8 reg_spm_infra_req_reserved_mask_b;
u8 reg_spm_apsrc_req_reserved_mask_b;
u8 reg_spm_vrf18_req_reserved_mask_b;
u8 reg_spm_ddr_en_reserved_mask_b;
u8 reg_mcupm_srcclkena_mask_b;
u8 reg_mcupm_infra_req_mask_b;
u8 reg_mcupm_apsrc_req_mask_b;
u8 reg_mcupm_vrf18_req_mask_b;
u8 reg_mcupm_ddr_en_mask_b;
u8 reg_msdc0_srcclkena_mask_b;
u8 reg_msdc0_infra_req_mask_b;
u8 reg_msdc0_apsrc_req_mask_b;
u8 reg_msdc0_vrf18_req_mask_b;
u8 reg_msdc0_ddr_en_mask_b;
u8 reg_msdc1_srcclkena_mask_b;
u8 reg_msdc1_infra_req_mask_b;
u8 reg_msdc1_apsrc_req_mask_b;
u8 reg_msdc1_vrf18_req_mask_b;
u8 reg_msdc1_ddr_en_mask_b;
/* SPM_SRC4_MASK */
u32 ccif_event_mask_b;
u8 reg_bak_psri_srcclkena_mask_b;
u8 reg_bak_psri_infra_req_mask_b;
u8 reg_bak_psri_apsrc_req_mask_b;
u8 reg_bak_psri_vrf18_req_mask_b;
u8 reg_bak_psri_ddr_en_mask_b;
u8 reg_dramc0_md32_infra_req_mask_b;
u8 reg_dramc0_md32_vrf18_req_mask_b;
u8 reg_dramc1_md32_infra_req_mask_b;
u8 reg_dramc1_md32_vrf18_req_mask_b;
u8 reg_conn_srcclkenb2pwrap_mask_b;
u8 reg_dramc0_md32_wakeup_mask;
u8 reg_dramc1_md32_wakeup_mask;
/* SPM_SRC5_MASK */
u32 reg_mcusys_merge_apsrc_req_mask_b;
u32 reg_mcusys_merge_ddr_en_mask_b;
u8 reg_msdc2_srcclkena_mask_b;
u8 reg_msdc2_infra_req_mask_b;
u8 reg_msdc2_apsrc_req_mask_b;
u8 reg_msdc2_vrf18_req_mask_b;
u8 reg_msdc2_ddr_en_mask_b;
u8 reg_pcie_srcclkena_mask_b;
u8 reg_pcie_infra_req_mask_b;
u8 reg_pcie_apsrc_req_mask_b;
u8 reg_pcie_vrf18_req_mask_b;
u8 reg_pcie_ddr_en_mask_b;
/* SPM_WAKEUP_EVENT_MASK */
u32 reg_wakeup_event_mask;
/* SPM_WAKEUP_EVENT_EXT_MASK */
u32 reg_ext_wakeup_event_mask;
/* Auto-gen End */
};
enum { enum {
DISP_PWR_STA_MASK = 0x1 << 20, DISP_PWR_STA_MASK = 0x1 << 20,
@ -34,14 +333,14 @@ struct mtk_spm_regs {
u32 pcm_timer_val; u32 pcm_timer_val;
u32 pcm_wdt_val; u32 pcm_wdt_val;
u32 spm_src6_mask; u32 spm_src6_mask;
u32 reserved1[1]; u32 reserved0;
u32 spm_sw_rst_con; /* 0x0040 */ u32 spm_sw_rst_con;
u32 spm_sw_rst_con_set; u32 spm_sw_rst_con_set;
u32 spm_sw_rst_con_clr; u32 spm_sw_rst_con_clr;
u32 vs1_psr_mask_b; u32 vs1_psr_mask_b;
u32 vs2_psr_mask_b; u32 vs2_psr_mask_b;
u32 reserved2[12]; u32 reserved1[12];
u32 md32_clk_con; /* 0x0084 */ u32 md32_clk_con;
u32 spm_sram_rsv_con; u32 spm_sram_rsv_con;
u32 spm_swint; u32 spm_swint;
u32 spm_swint_set; u32 spm_swint_set;
@ -77,27 +376,27 @@ struct mtk_spm_regs {
u32 pcm_reg6_data; u32 pcm_reg6_data;
u32 pcm_reg7_data; u32 pcm_reg7_data;
u32 pcm_reg13_data; u32 pcm_reg13_data;
u32 src_req_sta_0; u32 src_req_sta0;
u32 src_req_sta_1; u32 src_req_sta1;
u32 src_req_sta_2; u32 src_req_sta2;
u32 pcm_timer_out; u32 pcm_timer_out;
u32 pcm_wdt_out; u32 pcm_wdt_out;
u32 spm_irq_sta; u32 spm_irq_sta;
u32 src_req_sta_4; u32 src_req_sta4;
u32 md32pcm_wakeup_sta; u32 md32pcm_wakeup_sta;
u32 md32pcm_event_sta; u32 md32pcm_event_sta;
u32 spm_wakeup_sta; u32 spm_wakeup_sta;
u32 spm_wakeup_ext_sta; u32 spm_wakeup_ext_sta;
u32 spm_wakeup_misc; u32 spm_wakeup_misc;
u32 mm_dvfs_halt; u32 mm_dvfs_halt;
u32 reserved3[2]; u32 reserved2[2];
u32 bus_protect_rdy; /* 0x0150 */ u32 bus_protect_rdy;
u32 bus_protect1_rdy; u32 bus_protect1_rdy;
u32 bus_protect2_rdy; u32 bus_protect2_rdy;
u32 bus_protect3_rdy; u32 bus_protect3_rdy;
u32 subsys_idle_sta; u32 subsys_idle_sta;
u32 pcm_sta; u32 pcm_sta;
u32 src_req_sta_3; u32 src_req_sta3;
u32 pwr_status; u32 pwr_status;
u32 pwr_status_2nd; u32 pwr_status_2nd;
u32 cpu_pwr_status; u32 cpu_pwr_status;
@ -109,15 +408,15 @@ struct mtk_spm_regs {
u32 spm_ddren_event_count_sta; u32 spm_ddren_event_count_sta;
u32 md32pcm_sta; u32 md32pcm_sta;
u32 md32pcm_pc; u32 md32pcm_pc;
u32 reserved4[3]; u32 reserved3[3];
u32 dvfsrc_event_sta; /* 0x01a4 */ u32 dvfsrc_event_sta;
u32 bus_protect4_rdy; u32 bus_protect4_rdy;
u32 bus_protect5_rdy; u32 bus_protect5_rdy;
u32 bus_protect6_rdy; u32 bus_protect6_rdy;
u32 bus_protect7_rdy; u32 bus_protect7_rdy;
u32 bus_protect8_rdy; u32 bus_protect8_rdy;
u32 reserved5[5]; u32 reserved4[5];
u32 spm_twam_last_sta0; /* 0x01d0 */ u32 spm_twam_last_sta0;
u32 spm_twam_last_sta1; u32 spm_twam_last_sta1;
u32 spm_twam_last_sta2; u32 spm_twam_last_sta2;
u32 spm_twam_last_sta3; u32 spm_twam_last_sta3;
@ -139,8 +438,8 @@ struct mtk_spm_regs {
u32 spm_cpu5_pwr_con; u32 spm_cpu5_pwr_con;
u32 spm_cpu6_pwr_con; u32 spm_cpu6_pwr_con;
u32 spm_cpu7_pwr_con; u32 spm_cpu7_pwr_con;
u32 reserved6[1]; u32 reserved5;
u32 armpll_clk_con; /* 0x022c */ u32 armpll_clk_con;
u32 mcusys_idle_sta; u32 mcusys_idle_sta;
u32 gic_wakeup_sta; u32 gic_wakeup_sta;
u32 cpu_spare_con; u32 cpu_spare_con;
@ -150,8 +449,8 @@ struct mtk_spm_regs {
u32 ext_int_wakeup_req; u32 ext_int_wakeup_req;
u32 ext_int_wakeup_req_set; u32 ext_int_wakeup_req_set;
u32 ext_int_wakeup_req_clr; u32 ext_int_wakeup_req_clr;
u32 reserved7[3]; u32 reserved6[3];
u32 mp0_cpu0_irq_mask; /* 0x0260 */ u32 mp0_cpu0_irq_mask;
u32 mp0_cpu1_irq_mask; u32 mp0_cpu1_irq_mask;
u32 mp0_cpu2_irq_mask; u32 mp0_cpu2_irq_mask;
u32 mp0_cpu3_irq_mask; u32 mp0_cpu3_irq_mask;
@ -169,8 +468,8 @@ struct mtk_spm_regs {
u32 mp0_cpu7_wfi_en; u32 mp0_cpu7_wfi_en;
u32 root_cputop_addr; u32 root_cputop_addr;
u32 root_core_addr; u32 root_core_addr;
u32 reserved8[10]; u32 reserved7[10];
u32 spm2sw_mailbox_0; /* 0x02d0 */ u32 spm2sw_mailbox_0;
u32 spm2sw_mailbox_1; u32 spm2sw_mailbox_1;
u32 spm2sw_mailbox_2; u32 spm2sw_mailbox_2;
u32 spm2sw_mailbox_3; u32 spm2sw_mailbox_3;
@ -227,22 +526,151 @@ struct mtk_spm_regs {
u32 debugtop_sram_con; u32 debugtop_sram_con;
u32 dp_tx_pwr_con; u32 dp_tx_pwr_con;
u32 dpmaif_sram_con; u32 dpmaif_sram_con;
u32 dpy_shu2_sram_con; u32 dpy_shu2_con;
u32 dramc_mcu2_sram_con; u32 dramc_mcu2_sram_con;
u32 dramc_mcu_sram_con; u32 dramc_mcu_sram_con;
u32 mcupm_pwr_con; u32 mcupm_pwr_con;
u32 dpy2_pwr_con; u32 dpy2_pwr_con;
u32 peri_pwr_con; u32 peri_pwr_con;
u32 reserved8[13];
u32 spm_mem_ck_sel;
u32 spm_bus_protect_mask_b;
u32 spm_bus_protect1_mask_b;
u32 spm_bus_protect2_mask_b;
u32 spm_bus_protect3_mask_b;
u32 spm_bus_protect4_mask_b;
u32 spm_emi_bw_mode;
u32 ap2md_peer_wakeup;
u32 ulposc_con;
u32 spm2mm_con;
u32 spm_bus_protect5_mask_b;
u32 spm2mcupm_con;
u32 ap_mdsrc_req;
u32 spm2emi_enter_ulpm;
u32 spm2md_dvfs_con;
u32 md2spm_dvfs_con;
u32 spm_bus_protect6_mask_b;
u32 spm_bus_protect7_mask_b;
u32 spm_bus_protect8_mask_b;
u32 spm_pll_con;
u32 cpu_dvfs_req;
u32 spm_dram_mcu_sw_con0;
u32 spm_dram_mcu_sw_con1;
u32 spm_dram_mcu_sw_con2;
u32 spm_dram_mcu_sw_con3;
u32 spm_dram_mcu_sw_con4;
u32 spm_dram_mcu_sta_0;
u32 spm_dram_mcu_sta_1;
u32 spm_dram_mcu_sta_2;
u32 spm_dram_mcu_sw_sel_0;
u32 relay_dvfs_level;
u32 reserved9;
u32 dramc_dpy_clk_sw_con_0;
u32 dramc_dpy_clk_sw_con_1;
u32 dramc_dpy_clk_sw_con_2;
u32 dramc_dpy_clk_sw_con_3;
u32 dramc_dpy_clk_sw_sel_0;
u32 dramc_dpy_clk_sw_sel_1;
u32 dramc_dpy_clk_sw_sel_2;
u32 dramc_dpy_clk_sw_sel_3;
u32 dramc_dpy_clk_spm_con;
u32 spm_dvfs_level;
u32 spm_cirq_con;
u32 spm_dvfs_misc;
u32 spm_vs1_vs2_rc_con;
u32 rg_module_sw_cg_0_mask_req_0;
u32 rg_module_sw_cg_0_mask_req_1;
u32 rg_module_sw_cg_0_mask_req_2;
u32 rg_module_sw_cg_1_mask_req_0;
u32 rg_module_sw_cg_1_mask_req_1;
u32 rg_module_sw_cg_1_mask_req_2;
u32 rg_module_sw_cg_2_mask_req_0;
u32 rg_module_sw_cg_2_mask_req_1;
u32 rg_module_sw_cg_2_mask_req_2;
u32 rg_module_sw_cg_3_mask_req_0;
u32 rg_module_sw_cg_3_mask_req_1;
u32 rg_module_sw_cg_3_mask_req_2;
u32 pwr_status_mask_req_0;
u32 pwr_status_mask_req_1;
u32 pwr_status_mask_req_2;
u32 spm_cg_check_con;
u32 spm_src_rdy_sta;
u32 spm_dvs_dfs_level;
u32 spm_force_dvfs;
u32 reserved10[64];
u32 spm_sw_flag_0;
u32 spm_sw_debug_0;
u32 spm_sw_flag_1;
u32 reserved11[8];
u32 spm_sw_rsv_7;
u32 spm_sw_rsv_8;
u32 reserved12[203];
u32 spm_ack_chk_con_3;
u32 spm_ack_chk_pc_3;
u32 spm_ack_chk_sel_3;
u32 spm_ack_chk_timer_3;
u32 reserved13[7];
u32 sys_timer_con;
u32 reserved14[28];
u32 md32pcm_cfgreg_sw_rstn;
u32 reserved15[127];
u32 md32pcm_dma0_src;
u32 md32pcm_dma0_dst;
u32 md32pcm_dma0_wppt;
u32 md32pcm_dma0_wpto;
u32 md32pcm_dma0_count;
u32 md32pcm_dma0_con;
u32 md32pcm_dma0_start;
u32 reserved16[2];
u32 md32pcm_dma0_rlct;
}; };
check_member(mtk_spm_regs, poweron_config_set, 0x0);
check_member(mtk_spm_regs, md32_clk_con, 0x0084); check_member(mtk_spm_regs, vs2_psr_mask_b, 0x50);
check_member(mtk_spm_regs, bus_protect_rdy, 0x0150); check_member(mtk_spm_regs, md32_clk_con, 0x84);
check_member(mtk_spm_regs, dvfsrc_event_sta, 0x01a4); check_member(mtk_spm_regs, mm_dvfs_halt, 0x144);
check_member(mtk_spm_regs, spm_twam_last_sta0, 0x01d0); check_member(mtk_spm_regs, bus_protect_rdy, 0x150);
check_member(mtk_spm_regs, mp0_cpu0_irq_mask, 0x0260); check_member(mtk_spm_regs, md32pcm_pc, 0x194);
check_member(mtk_spm_regs, spm2sw_mailbox_0, 0x02d0); check_member(mtk_spm_regs, dvfsrc_event_sta, 0x1a4);
check_member(mtk_spm_regs, peri_pwr_con, 0x03c8); check_member(mtk_spm_regs, bus_protect8_rdy, 0x1b8);
check_member(mtk_spm_regs, spm_twam_last_sta0, 0x1d0);
check_member(mtk_spm_regs, ext_int_wakeup_req_clr, 0x250);
check_member(mtk_spm_regs, mp0_cpu0_irq_mask, 0x260);
check_member(mtk_spm_regs, root_core_addr, 0x2a4);
check_member(mtk_spm_regs, spm2sw_mailbox_0, 0x2d0);
check_member(mtk_spm_regs, peri_pwr_con, 0x3c8);
check_member(mtk_spm_regs, spm_mem_ck_sel, 0x400);
check_member(mtk_spm_regs, spm_force_dvfs, 0x4fc);
check_member(mtk_spm_regs, spm_sw_flag_0, 0x600);
check_member(mtk_spm_regs, spm_sw_flag_1, 0x608);
check_member(mtk_spm_regs, spm_sw_rsv_7, 0x62c);
check_member(mtk_spm_regs, spm_sw_rsv_8, 0x630);
check_member(mtk_spm_regs, spm_ack_chk_con_3, 0x960);
check_member(mtk_spm_regs, spm_ack_chk_timer_3, 0x96c);
check_member(mtk_spm_regs, sys_timer_con, 0x98c);
check_member(mtk_spm_regs, md32pcm_cfgreg_sw_rstn, 0xa00);
check_member(mtk_spm_regs, md32pcm_dma0_src, 0xc00);
check_member(mtk_spm_regs, md32pcm_dma0_dst, 0xc04);
check_member(mtk_spm_regs, md32pcm_dma0_wppt, 0xc08);
check_member(mtk_spm_regs, md32pcm_dma0_wpto, 0xc0c);
check_member(mtk_spm_regs, md32pcm_dma0_count, 0xc10);
check_member(mtk_spm_regs, md32pcm_dma0_con, 0xc14);
check_member(mtk_spm_regs, md32pcm_dma0_start, 0xc18);
check_member(mtk_spm_regs, md32pcm_dma0_rlct, 0xc24);
static struct mtk_spm_regs *const mtk_spm = (void *)SPM_BASE; static struct mtk_spm_regs *const mtk_spm = (void *)SPM_BASE;
struct pcm_desc {
u32 pmem_words;
u32 total_words;
u32 pmem_start;
u32 dmem_start;
};
struct dyna_load_pcm {
u8 *buf; /* binary array */
struct pcm_desc desc;
};
int spm_init(void);
#endif /* SOC_MEDIATEK_MT8192_SPM_H */ #endif /* SOC_MEDIATEK_MT8192_SPM_H */

View File

@ -0,0 +1,654 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <assert.h>
#include <cbfs.h>
#include <console/console.h>
#include <delay.h>
#include <device/mmio.h>
#include <soc/mcu_common.h>
#include <soc/spm.h>
#include <soc/symbols.h>
#include <timer.h>
#define SPM_SYSTEM_BASE_OFFSET 0x40000000
#define SPMFW_HEADER_SIZE 16
static const struct pwr_ctrl spm_init_ctrl = {
/* Auto-gen Start */
.pcm_flags = SPM_FLAG_DISABLE_VCORE_DVS | SPM_FLAG_DISABLE_VCORE_DFS |
SPM_FLAG_RUN_COMMON_SCENARIO,
/* SPM_SRC6_MASK */
.reg_dpmaif_srcclkena_mask_b = 1,
.reg_dpmaif_infra_req_mask_b = 1,
.reg_dpmaif_apsrc_req_mask_b = 1,
.reg_dpmaif_vrf18_req_mask_b = 1,
.reg_dpmaif_ddr_en_mask_b = 1,
/* SPM_SRC_REQ */
.reg_spm_ddr_en_req = 1,
/* SPM_SRC_MASK */
.reg_md_srcclkena_0_mask_b = 1,
.reg_md_apsrc2infra_req_0_mask_b = 1,
.reg_md_apsrc_req_0_mask_b = 1,
.reg_md_vrf18_req_0_mask_b = 1,
.reg_md_ddr_en_0_mask_b = 1,
.reg_conn_srcclkena_mask_b = 1,
.reg_conn_infra_req_mask_b = 1,
.reg_conn_apsrc_req_mask_b = 1,
.reg_conn_vrf18_req_mask_b = 1,
.reg_conn_ddr_en_mask_b = 1,
.reg_srcclkeni0_srcclkena_mask_b = 1,
.reg_srcclkeni0_infra_req_mask_b = 1,
.reg_infrasys_ddr_en_mask_b = 1,
.reg_md32_srcclkena_mask_b = 1,
.reg_md32_infra_req_mask_b = 1,
.reg_md32_apsrc_req_mask_b = 1,
.reg_md32_vrf18_req_mask_b = 1,
.reg_md32_ddr_en_mask_b = 1,
/* SPM_SRC2_MASK */
.reg_scp_srcclkena_mask_b = 1,
.reg_scp_infra_req_mask_b = 1,
.reg_scp_apsrc_req_mask_b = 1,
.reg_scp_vrf18_req_mask_b = 1,
.reg_scp_ddr_en_mask_b = 1,
.reg_audio_dsp_srcclkena_mask_b = 1,
.reg_audio_dsp_infra_req_mask_b = 1,
.reg_audio_dsp_apsrc_req_mask_b = 1,
.reg_audio_dsp_vrf18_req_mask_b = 1,
.reg_audio_dsp_ddr_en_mask_b = 1,
.reg_ufs_srcclkena_mask_b = 1,
.reg_ufs_infra_req_mask_b = 1,
.reg_ufs_apsrc_req_mask_b = 1,
.reg_ufs_vrf18_req_mask_b = 1,
.reg_ufs_ddr_en_mask_b = 1,
.reg_disp0_apsrc_req_mask_b = 1,
.reg_disp0_ddr_en_mask_b = 1,
.reg_disp1_apsrc_req_mask_b = 1,
.reg_disp1_ddr_en_mask_b = 1,
.reg_gce_infra_req_mask_b = 1,
.reg_gce_apsrc_req_mask_b = 1,
.reg_gce_vrf18_req_mask_b = 1,
.reg_gce_ddr_en_mask_b = 1,
.reg_apu_srcclkena_mask_b = 1,
.reg_apu_infra_req_mask_b = 1,
.reg_apu_apsrc_req_mask_b = 1,
.reg_apu_vrf18_req_mask_b = 1,
.reg_apu_ddr_en_mask_b = 1,
/* SPM_SRC3_MASK */
.reg_dvfsrc_event_trigger_mask_b = 1,
.reg_csyspwrreq_mask = 1,
.reg_mcupm_srcclkena_mask_b = 1,
.reg_mcupm_infra_req_mask_b = 1,
.reg_mcupm_apsrc_req_mask_b = 1,
.reg_mcupm_vrf18_req_mask_b = 1,
.reg_mcupm_ddr_en_mask_b = 1,
.reg_msdc0_srcclkena_mask_b = 1,
.reg_msdc0_infra_req_mask_b = 1,
.reg_msdc0_apsrc_req_mask_b = 1,
.reg_msdc0_vrf18_req_mask_b = 1,
.reg_msdc0_ddr_en_mask_b = 1,
.reg_msdc1_srcclkena_mask_b = 1,
.reg_msdc1_infra_req_mask_b = 1,
.reg_msdc1_apsrc_req_mask_b = 1,
.reg_msdc1_vrf18_req_mask_b = 1,
.reg_msdc1_ddr_en_mask_b = 1,
/* SPM_SRC4_MASK */
.ccif_event_mask_b = 0xFFF,
.reg_dramc0_md32_infra_req_mask_b = 1,
.reg_dramc1_md32_infra_req_mask_b = 1,
.reg_dramc0_md32_wakeup_mask = 1,
.reg_dramc1_md32_wakeup_mask = 1,
/* SPM_SRC5_MASK */
.reg_mcusys_merge_apsrc_req_mask_b = 0x11,
.reg_mcusys_merge_ddr_en_mask_b = 0x11,
.reg_msdc2_srcclkena_mask_b = 1,
.reg_msdc2_infra_req_mask_b = 1,
.reg_msdc2_apsrc_req_mask_b = 1,
.reg_msdc2_vrf18_req_mask_b = 1,
.reg_msdc2_ddr_en_mask_b = 1,
.reg_pcie_srcclkena_mask_b = 1,
.reg_pcie_infra_req_mask_b = 1,
.reg_pcie_apsrc_req_mask_b = 1,
.reg_pcie_vrf18_req_mask_b = 1,
.reg_pcie_ddr_en_mask_b = 1,
/* SPM_WAKEUP_EVENT_MASK */
.reg_wakeup_event_mask = 0xEFFFFFFF,
/* SPM_WAKEUP_EVENT_EXT_MASK */
.reg_ext_wakeup_event_mask = 0xFFFFFFFF,
/* Auto-gen End */
};
static void spm_set_power_control(const struct pwr_ctrl *pwrctrl)
{
/* Auto-gen Start */
/* SPM_AP_STANDBY_CON */
write32(&mtk_spm->spm_ap_standby_con,
((pwrctrl->reg_wfi_op & 0x1) << 0) |
((pwrctrl->reg_wfi_type & 0x1) << 1) |
((pwrctrl->reg_mp0_cputop_idle_mask & 0x1) << 2) |
((pwrctrl->reg_mp1_cputop_idle_mask & 0x1) << 3) |
((pwrctrl->reg_mcusys_idle_mask & 0x1) << 4) |
((pwrctrl->reg_md_apsrc_1_sel & 0x1) << 25) |
((pwrctrl->reg_md_apsrc_0_sel & 0x1) << 26) |
((pwrctrl->reg_conn_apsrc_sel & 0x1) << 29));
/* SPM_SRC6_MASK */
write32(&mtk_spm->spm_src6_mask,
((pwrctrl->reg_dpmaif_srcclkena_mask_b & 0x1) << 0) |
((pwrctrl->reg_dpmaif_infra_req_mask_b & 0x1) << 1) |
((pwrctrl->reg_dpmaif_apsrc_req_mask_b & 0x1) << 2) |
((pwrctrl->reg_dpmaif_vrf18_req_mask_b & 0x1) << 3) |
((pwrctrl->reg_dpmaif_ddr_en_mask_b & 0x1) << 4));
/* SPM_SRC_REQ */
write32(&mtk_spm->spm_src_req,
((pwrctrl->reg_spm_apsrc_req & 0x1) << 0) |
((pwrctrl->reg_spm_f26m_req & 0x1) << 1) |
((pwrctrl->reg_spm_infra_req & 0x1) << 3) |
((pwrctrl->reg_spm_vrf18_req & 0x1) << 4) |
((pwrctrl->reg_spm_ddr_en_req & 0x1) << 7) |
((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
/* SPM_SRC_MASK */
write32(&mtk_spm->spm_src_mask,
((pwrctrl->reg_md_srcclkena_0_mask_b & 0x1) << 0) |
((pwrctrl->reg_md_srcclkena2infra_req_0_mask_b & 0x1) << 1) |
((pwrctrl->reg_md_apsrc2infra_req_0_mask_b & 0x1) << 2) |
((pwrctrl->reg_md_apsrc_req_0_mask_b & 0x1) << 3) |
((pwrctrl->reg_md_vrf18_req_0_mask_b & 0x1) << 4) |
((pwrctrl->reg_md_ddr_en_0_mask_b & 0x1) << 5) |
((pwrctrl->reg_md_srcclkena_1_mask_b & 0x1) << 6) |
((pwrctrl->reg_md_srcclkena2infra_req_1_mask_b & 0x1) << 7) |
((pwrctrl->reg_md_apsrc2infra_req_1_mask_b & 0x1) << 8) |
((pwrctrl->reg_md_apsrc_req_1_mask_b & 0x1) << 9) |
((pwrctrl->reg_md_vrf18_req_1_mask_b & 0x1) << 10) |
((pwrctrl->reg_md_ddr_en_1_mask_b & 0x1) << 11) |
((pwrctrl->reg_conn_srcclkena_mask_b & 0x1) << 12) |
((pwrctrl->reg_conn_srcclkenb_mask_b & 0x1) << 13) |
((pwrctrl->reg_conn_infra_req_mask_b & 0x1) << 14) |
((pwrctrl->reg_conn_apsrc_req_mask_b & 0x1) << 15) |
((pwrctrl->reg_conn_vrf18_req_mask_b & 0x1) << 16) |
((pwrctrl->reg_conn_ddr_en_mask_b & 0x1) << 17) |
((pwrctrl->reg_conn_vfe28_mask_b & 0x1) << 18) |
((pwrctrl->reg_srcclkeni0_srcclkena_mask_b & 0x1) << 19) |
((pwrctrl->reg_srcclkeni0_infra_req_mask_b & 0x1) << 20) |
((pwrctrl->reg_srcclkeni1_srcclkena_mask_b & 0x1) << 21) |
((pwrctrl->reg_srcclkeni1_infra_req_mask_b & 0x1) << 22) |
((pwrctrl->reg_srcclkeni2_srcclkena_mask_b & 0x1) << 23) |
((pwrctrl->reg_srcclkeni2_infra_req_mask_b & 0x1) << 24) |
((pwrctrl->reg_infrasys_apsrc_req_mask_b & 0x1) << 25) |
((pwrctrl->reg_infrasys_ddr_en_mask_b & 0x1) << 26) |
((pwrctrl->reg_md32_srcclkena_mask_b & 0x1) << 27) |
((pwrctrl->reg_md32_infra_req_mask_b & 0x1) << 28) |
((pwrctrl->reg_md32_apsrc_req_mask_b & 0x1) << 29) |
((pwrctrl->reg_md32_vrf18_req_mask_b & 0x1) << 30) |
((pwrctrl->reg_md32_ddr_en_mask_b & 0x1) << 31));
/* SPM_SRC2_MASK */
write32(&mtk_spm->spm_src2_mask,
((pwrctrl->reg_scp_srcclkena_mask_b & 0x1) << 0) |
((pwrctrl->reg_scp_infra_req_mask_b & 0x1) << 1) |
((pwrctrl->reg_scp_apsrc_req_mask_b & 0x1) << 2) |
((pwrctrl->reg_scp_vrf18_req_mask_b & 0x1) << 3) |
((pwrctrl->reg_scp_ddr_en_mask_b & 0x1) << 4) |
((pwrctrl->reg_audio_dsp_srcclkena_mask_b & 0x1) << 5) |
((pwrctrl->reg_audio_dsp_infra_req_mask_b & 0x1) << 6) |
((pwrctrl->reg_audio_dsp_apsrc_req_mask_b & 0x1) << 7) |
((pwrctrl->reg_audio_dsp_vrf18_req_mask_b & 0x1) << 8) |
((pwrctrl->reg_audio_dsp_ddr_en_mask_b & 0x1) << 9) |
((pwrctrl->reg_ufs_srcclkena_mask_b & 0x1) << 10) |
((pwrctrl->reg_ufs_infra_req_mask_b & 0x1) << 11) |
((pwrctrl->reg_ufs_apsrc_req_mask_b & 0x1) << 12) |
((pwrctrl->reg_ufs_vrf18_req_mask_b & 0x1) << 13) |
((pwrctrl->reg_ufs_ddr_en_mask_b & 0x1) << 14) |
((pwrctrl->reg_disp0_apsrc_req_mask_b & 0x1) << 15) |
((pwrctrl->reg_disp0_ddr_en_mask_b & 0x1) << 16) |
((pwrctrl->reg_disp1_apsrc_req_mask_b & 0x1) << 17) |
((pwrctrl->reg_disp1_ddr_en_mask_b & 0x1) << 18) |
((pwrctrl->reg_gce_infra_req_mask_b & 0x1) << 19) |
((pwrctrl->reg_gce_apsrc_req_mask_b & 0x1) << 20) |
((pwrctrl->reg_gce_vrf18_req_mask_b & 0x1) << 21) |
((pwrctrl->reg_gce_ddr_en_mask_b & 0x1) << 22) |
((pwrctrl->reg_apu_srcclkena_mask_b & 0x1) << 23) |
((pwrctrl->reg_apu_infra_req_mask_b & 0x1) << 24) |
((pwrctrl->reg_apu_apsrc_req_mask_b & 0x1) << 25) |
((pwrctrl->reg_apu_vrf18_req_mask_b & 0x1) << 26) |
((pwrctrl->reg_apu_ddr_en_mask_b & 0x1) << 27) |
((pwrctrl->reg_cg_check_srcclkena_mask_b & 0x1) << 28) |
((pwrctrl->reg_cg_check_apsrc_req_mask_b & 0x1) << 29) |
((pwrctrl->reg_cg_check_vrf18_req_mask_b & 0x1) << 30) |
((pwrctrl->reg_cg_check_ddr_en_mask_b & 0x1) << 31));
/* SPM_SRC3_MASK */
write32(&mtk_spm->spm_src3_mask,
((pwrctrl->reg_dvfsrc_event_trigger_mask_b & 0x1) << 0) |
((pwrctrl->reg_sw2spm_int0_mask_b & 0x1) << 1) |
((pwrctrl->reg_sw2spm_int1_mask_b & 0x1) << 2) |
((pwrctrl->reg_sw2spm_int2_mask_b & 0x1) << 3) |
((pwrctrl->reg_sw2spm_int3_mask_b & 0x1) << 4) |
((pwrctrl->reg_sc_adsp2spm_wakeup_mask_b & 0x1) << 5) |
((pwrctrl->reg_sc_sspm2spm_wakeup_mask_b & 0xf) << 6) |
((pwrctrl->reg_sc_scp2spm_wakeup_mask_b & 0x1) << 10) |
((pwrctrl->reg_csyspwrreq_mask & 0x1) << 11) |
((pwrctrl->reg_spm_srcclkena_reserved_mask_b & 0x1) << 12) |
((pwrctrl->reg_spm_infra_req_reserved_mask_b & 0x1) << 13) |
((pwrctrl->reg_spm_apsrc_req_reserved_mask_b & 0x1) << 14) |
((pwrctrl->reg_spm_vrf18_req_reserved_mask_b & 0x1) << 15) |
((pwrctrl->reg_spm_ddr_en_reserved_mask_b & 0x1) << 16) |
((pwrctrl->reg_mcupm_srcclkena_mask_b & 0x1) << 17) |
((pwrctrl->reg_mcupm_infra_req_mask_b & 0x1) << 18) |
((pwrctrl->reg_mcupm_apsrc_req_mask_b & 0x1) << 19) |
((pwrctrl->reg_mcupm_vrf18_req_mask_b & 0x1) << 20) |
((pwrctrl->reg_mcupm_ddr_en_mask_b & 0x1) << 21) |
((pwrctrl->reg_msdc0_srcclkena_mask_b & 0x1) << 22) |
((pwrctrl->reg_msdc0_infra_req_mask_b & 0x1) << 23) |
((pwrctrl->reg_msdc0_apsrc_req_mask_b & 0x1) << 24) |
((pwrctrl->reg_msdc0_vrf18_req_mask_b & 0x1) << 25) |
((pwrctrl->reg_msdc0_ddr_en_mask_b & 0x1) << 26) |
((pwrctrl->reg_msdc1_srcclkena_mask_b & 0x1) << 27) |
((pwrctrl->reg_msdc1_infra_req_mask_b & 0x1) << 28) |
((pwrctrl->reg_msdc1_apsrc_req_mask_b & 0x1) << 29) |
((pwrctrl->reg_msdc1_vrf18_req_mask_b & 0x1) << 30) |
((pwrctrl->reg_msdc1_ddr_en_mask_b & 0x1) << 31));
/* SPM_SRC4_MASK */
write32(&mtk_spm->spm_src4_mask,
((pwrctrl->ccif_event_mask_b & 0xffff) << 0) |
((pwrctrl->reg_bak_psri_srcclkena_mask_b & 0x1) << 16) |
((pwrctrl->reg_bak_psri_infra_req_mask_b & 0x1) << 17) |
((pwrctrl->reg_bak_psri_apsrc_req_mask_b & 0x1) << 18) |
((pwrctrl->reg_bak_psri_vrf18_req_mask_b & 0x1) << 19) |
((pwrctrl->reg_bak_psri_ddr_en_mask_b & 0x1) << 20) |
((pwrctrl->reg_dramc0_md32_infra_req_mask_b & 0x1) << 21) |
((pwrctrl->reg_dramc0_md32_vrf18_req_mask_b & 0x1) << 22) |
((pwrctrl->reg_dramc1_md32_infra_req_mask_b & 0x1) << 23) |
((pwrctrl->reg_dramc1_md32_vrf18_req_mask_b & 0x1) << 24) |
((pwrctrl->reg_conn_srcclkenb2pwrap_mask_b & 0x1) << 25) |
((pwrctrl->reg_dramc0_md32_wakeup_mask & 0x1) << 26) |
((pwrctrl->reg_dramc1_md32_wakeup_mask & 0x1) << 27));
/* SPM_SRC5_MASK */
write32(&mtk_spm->spm_src5_mask,
((pwrctrl->reg_mcusys_merge_apsrc_req_mask_b & 0x1ff) << 0) |
((pwrctrl->reg_mcusys_merge_ddr_en_mask_b & 0x1ff) << 9) |
((pwrctrl->reg_msdc2_srcclkena_mask_b & 0x1) << 18) |
((pwrctrl->reg_msdc2_infra_req_mask_b & 0x1) << 19) |
((pwrctrl->reg_msdc2_apsrc_req_mask_b & 0x1) << 20) |
((pwrctrl->reg_msdc2_vrf18_req_mask_b & 0x1) << 21) |
((pwrctrl->reg_msdc2_ddr_en_mask_b & 0x1) << 22) |
((pwrctrl->reg_pcie_srcclkena_mask_b & 0x1) << 23) |
((pwrctrl->reg_pcie_infra_req_mask_b & 0x1) << 24) |
((pwrctrl->reg_pcie_apsrc_req_mask_b & 0x1) << 25) |
((pwrctrl->reg_pcie_vrf18_req_mask_b & 0x1) << 26) |
((pwrctrl->reg_pcie_ddr_en_mask_b & 0x1) << 27));
/* SPM_WAKEUP_EVENT_MASK */
write32(&mtk_spm->spm_wakeup_event_mask,
((pwrctrl->reg_wakeup_event_mask & 0xffffffff) << 0));
/* SPM_WAKEUP_EVENT_EXT_MASK */
write32(&mtk_spm->spm_wakeup_event_ext_mask,
((pwrctrl->reg_ext_wakeup_event_mask & 0xffffffff) << 0));
/* Auto-gen End */
}
static void spm_register_init(void)
{
/* Enable register control */
write32(&mtk_spm->poweron_config_set,
SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB);
/* Init power control register */
write32(&mtk_spm->spm_power_on_val1, POWER_ON_VAL1_DEF);
write32(&mtk_spm->pcm_pwr_io_en, 0);
/* Reset PCM */
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);
write32(&mtk_spm->pcm_con1,
SPM_REGWR_CFG_KEY | REG_EVENT_LOCK_EN_LSB |
REG_SPM_SRAM_ISOINT_B_LSB | RG_AHBMIF_APBEN_LSB |
REG_MD32_APB_INTERNAL_EN_LSB);
/* Initial SPM CLK control register */
setbits32(&mtk_spm->spm_clk_con, REG_SYSCLK1_SRC_MD2_SRCCLKENA);
/* Clean wakeup event raw status */
write32(&mtk_spm->spm_wakeup_event_mask, SPM_WAKEUP_EVENT_MASK_DEF);
/* Clean ISR status */
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);
/* Init r7 with POWER_ON_VAL1 */
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);
/* DDR EN de-bounce length to 5us */
write32(&mtk_spm->ddr_en_dbc_con0, DDR_EN_DBC_CON0_DEF);
write32(&mtk_spm->ddr_en_dbc_con1, REG_ALL_DDR_EN_DBC_EN_LSB);
/* Configure ARMPLL Control Mode for MCDI */
write32(&mtk_spm->armpll_clk_sel, ARMPLL_CLK_SEL_DEF);
/* Init for SPM Resource ACK */
write32(&mtk_spm->spm_resource_ack_con0, SPM_RESOURCE_ACK_CON0_DEF);
write32(&mtk_spm->spm_resource_ack_con1, SPM_RESOURCE_ACK_CON1_DEF);
write32(&mtk_spm->spm_resource_ack_con2, SPM_RESOURCE_ACK_CON2_DEF);
write32(&mtk_spm->spm_resource_ack_con3, SPM_RESOURCE_ACK_CON3_DEF);
/* Init VCORE DVFS Status */
clrsetbits32(&mtk_spm->spm_dvfs_misc,
SPM_DVFS_FORCE_ENABLE_LSB, SPM_DVFSRC_ENABLE_LSB);
write32(&mtk_spm->spm_dvfs_level, SPM_DVFS_LEVEL_DEF);
write32(&mtk_spm->spm_dvs_dfs_level, SPM_DVS_DFS_LEVEL_DEF);
write32(&mtk_spm->spm_ack_chk_sel_3, SPM_ACK_CHK_3_SEL_HW_S1);
write32(&mtk_spm->spm_ack_chk_timer_3, SPM_ACK_CHK_3_HW_S1_CNT);
/* Apm hw s1 state monitor pause */
clrsetbits32(&mtk_spm->spm_ack_chk_con_3,
SPM_ACK_CHK_3_CON_EN,
SPM_ACK_CHK_3_CON_HW_MODE_TRIG |
SPM_ACK_CHK_3_CON_CLR_ALL);
}
static void spm_set_sysclk_settle(void)
{
write32(&mtk_spm->spm_clk_settle, SPM_SYSCLK_SETTLE);
}
static void spm_code_swapping(void)
{
u32 mask;
mask = read32(&mtk_spm->spm_wakeup_event_mask);
write32(&mtk_spm->spm_wakeup_event_mask,
mask & ~SPM_WAKEUP_EVENT_MASK_BIT0);
write32(&mtk_spm->spm_cpu_wakeup_event, 1);
write32(&mtk_spm->spm_cpu_wakeup_event, 0);
write32(&mtk_spm->spm_wakeup_event_mask, mask);
}
static void spm_reset_and_init_pcm(void)
{
bool first_load_fw = true;
/* Check the SPM FW is run or not */
if (read32(&mtk_spm->md32pcm_cfgreg_sw_rstn) &
MD32PCM_CFGREG_SW_RSTN_RUN)
first_load_fw = false;
if (!first_load_fw) {
spm_code_swapping();
/* Backup PCM r0 -> SPM_POWER_ON_VAL0 before reset PCM */
write32(&mtk_spm->spm_power_on_val0,
read32(&mtk_spm->pcm_reg0_data));
}
/* Disable r0 and r7 to control power */
write32(&mtk_spm->pcm_pwr_io_en, 0);
/* Disable pcm timer after leaving FW */
clrsetbits32(&mtk_spm->pcm_con1,
RG_PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY);
/* Reset PCM */
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);
/* Init PCM_CON1 (disable PCM timer but keep PCM WDT setting) */
clrsetbits32(&mtk_spm->pcm_con1, ~RG_PCM_WDT_WAKE_LSB,
SPM_REGWR_CFG_KEY | REG_EVENT_LOCK_EN_LSB |
REG_SPM_SRAM_ISOINT_B_LSB | RG_AHBMIF_APBEN_LSB |
REG_MD32_APB_INTERNAL_EN_LSB);
}
static void spm_kick_im_to_fetch(const struct dyna_load_pcm *pcm)
{
uintptr_t ptr;
u32 dmem_words;
u32 pmem_words;
u32 total_words;
u32 pmem_start;
u32 dmem_start;
ptr = (uintptr_t)pcm->buf + SPM_SYSTEM_BASE_OFFSET;
pmem_words = pcm->desc.pmem_words;
total_words = pcm->desc.total_words;
dmem_words = total_words - pmem_words;
pmem_start = pcm->desc.pmem_start;
dmem_start = pcm->desc.dmem_start;
printk(BIOS_DEBUG, "%s: ptr = %#lx, pmem/dmem words = %#x/%#x\n",
__func__, (long)ptr, pmem_words, dmem_words);
/* DMA needs 16-byte aligned source data. */
assert(ptr % 16 == 0);
/* Program/Data must also be 16-byte (4-word) aligned. */
assert(pmem_words % 4 == 0);
assert(dmem_words % 4 == 0);
write32(&mtk_spm->md32pcm_dma0_src, ptr);
write32(&mtk_spm->md32pcm_dma0_dst, pmem_start);
write32(&mtk_spm->md32pcm_dma0_wppt, pmem_words);
write32(&mtk_spm->md32pcm_dma0_wpto, dmem_start);
write32(&mtk_spm->md32pcm_dma0_count, total_words);
write32(&mtk_spm->md32pcm_dma0_con, MD32PCM_DMA0_CON_VAL);
write32(&mtk_spm->md32pcm_dma0_start, MD32PCM_DMA0_START_VAL);
setbits32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
}
static void spm_init_pcm_register(void)
{
/* Init r0 with POWER_ON_VAL0 */
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);
/* Init r7 with POWER_ON_VAL1 */
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_parse_firmware(struct mtk_mcu *mcu)
{
size_t file_size, copy_size;
int offset;
u16 firmware_size;
struct dyna_load_pcm *pcm = (struct dyna_load_pcm *)mcu->priv;
file_size = mcu->run_size;
/*
* spmfw layout:
* u16 firmware_size
* u32 binary[firmware_size]
* struct pcm_desc descriptor
* char *version
*/
/* Firmware size */
offset = 0;
copy_size = sizeof(firmware_size);
memcpy(&firmware_size, mcu->load_buffer + offset, copy_size);
printk(BIOS_DEBUG, "SPM: binary array size = %#x\n", firmware_size);
/* Binary */
offset = SPMFW_HEADER_SIZE; /* binary start offset */
copy_size = firmware_size * sizeof(u32);
assert(offset < file_size);
pcm->buf = (u8 *)(mcu->load_buffer + offset);
/* Descriptor */
offset += copy_size;
assert(offset < file_size);
copy_size = sizeof(pcm->desc);
memcpy(&pcm->desc, mcu->load_buffer + offset, copy_size);
/* Firmware size and total words need to be the same */
assert(firmware_size == pcm->desc.total_words);
/* Version */
offset += copy_size;
assert(offset < file_size);
printk(BIOS_INFO, "SPM: spmfw (version %s)\n", (u8 *)mcu->load_buffer + offset);
}
static void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
{
u32 val, mask;
/* Toggle event counter clear */
setbits32(&mtk_spm->pcm_con1,
SPM_REGWR_CFG_KEY | SPM_EVENT_COUNTER_CLR_LSB);
/* Toggle for reset SYS TIMER start point */
setbits32(&mtk_spm->sys_timer_con, SYS_TIMER_START_EN_LSB);
if (pwrctrl->timer_val_cust == 0)
val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX;
else
val = pwrctrl->timer_val_cust;
write32(&mtk_spm->pcm_timer_val, val);
/* Disable pcm timer */
clrsetbits32(&mtk_spm->pcm_con1,
RG_PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY);
/* Unmask AP wakeup source */
if (pwrctrl->wake_src_cust == 0)
mask = pwrctrl->wake_src;
else
mask = pwrctrl->wake_src_cust;
if (pwrctrl->reg_csyspwrreq_mask)
mask &= ~SPM_WAKEUP_EVENT_MASK_CSYSPWREQ_B;
write32(&mtk_spm->spm_wakeup_event_mask, ~mask);
/* Unmask SPM ISR (keep TWAM setting) */
setbits32(&mtk_spm->spm_irq_mask, ISRM_RET_IRQ_AUX);
/* Toggle event counter clear */
clrsetbits32(&mtk_spm->pcm_con1,
SPM_EVENT_COUNTER_CLR_LSB, SPM_REGWR_CFG_KEY);
/* Toggle for reset SYS TIMER start point */
clrbits32(&mtk_spm->sys_timer_con, SYS_TIMER_START_EN_LSB);
}
static void spm_set_pcm_flags(const struct pwr_ctrl *pwrctrl)
{
u32 pcm_flags = pwrctrl->pcm_flags, pcm_flags1 = pwrctrl->pcm_flags1;
/* Set PCM flags and data */
if (pwrctrl->pcm_flags_cust_clr != 0)
pcm_flags &= ~pwrctrl->pcm_flags_cust_clr;
if (pwrctrl->pcm_flags_cust_set != 0)
pcm_flags |= pwrctrl->pcm_flags_cust_set;
if (pwrctrl->pcm_flags1_cust_clr != 0)
pcm_flags1 &= ~pwrctrl->pcm_flags1_cust_clr;
if (pwrctrl->pcm_flags1_cust_set != 0)
pcm_flags1 |= pwrctrl->pcm_flags1_cust_set;
write32(&mtk_spm->spm_sw_flag_0, pcm_flags);
write32(&mtk_spm->spm_sw_flag_1, pcm_flags1);
write32(&mtk_spm->spm_sw_rsv_7, pcm_flags);
write32(&mtk_spm->spm_sw_rsv_8, pcm_flags1);
}
static void spm_kick_pcm_to_run(const struct pwr_ctrl *pwrctrl)
{
/* Waiting for loading SPMFW done*/
while (read32(&mtk_spm->md32pcm_dma0_rlct) != 0x0)
;
/* Init register to match PCM expectation */
write32(&mtk_spm->spm_bus_protect_mask_b, SPM_BUS_PROTECT_MASK_B_DEF);
write32(&mtk_spm->spm_bus_protect2_mask_b,
SPM_BUS_PROTECT2_MASK_B_DEF);
write32(&mtk_spm->pcm_reg_data_ini, 0);
spm_set_pcm_flags(pwrctrl);
/* Kick PCM to run (only toggle PCM_KICK) */
setbits32(&mtk_spm->pcm_con0, SPM_REGWR_CFG_KEY | PCM_CK_EN_LSB);
/* Reset md32pcm */
setbits32(&mtk_spm->md32pcm_cfgreg_sw_rstn,
MD32PCM_CFGREG_SW_RSTN_RESET);
/* Waiting for SPM init done */
udelay(SPM_INIT_DONE_US);
}
static void reset_spm(struct mtk_mcu *mcu)
{
struct dyna_load_pcm *pcm = (struct dyna_load_pcm *)mcu->priv;
spm_parse_firmware(mcu);
spm_reset_and_init_pcm();
spm_kick_im_to_fetch(pcm);
spm_init_pcm_register();
spm_set_wakeup_event(&spm_init_ctrl);
spm_kick_pcm_to_run(&spm_init_ctrl);
}
static struct mtk_mcu spm = {
.firmware_name = CONFIG_SPM_FIRMWARE,
.reset = reset_spm,
};
int spm_init(void)
{
struct dyna_load_pcm pcm;
struct stopwatch sw;
stopwatch_init(&sw);
spm_register_init();
spm_set_power_control(&spm_init_ctrl);
spm_set_sysclk_settle();
spm.load_buffer = _dram_dma;
spm.buffer_size = REGION_SIZE(dram_dma);
spm.priv = (void *)&pcm;
if (mtk_init_mcu(&spm)) {
printk(BIOS_ERR, "SPM: %s: failed in mtk_init_mcu\n", __func__);
return -1;
}
printk(BIOS_INFO, "SPM: %s done in %ld msecs, spm pc = %#x\n",
__func__, stopwatch_duration_msecs(&sw),
read32(&mtk_spm->md32pcm_pc));
return 0;
}