GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,51 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Conditional makefile variable assignment
# Options depend on BUILD_TYPE variable
ifeq ($(BUILD_TYPE),release)
MTK_DEBUGSYS_LOCK := 1
MTK_GET_PERM_DIS := 1
ERRATA_KLEIN_2218950 := 0
ERRATA_KLEIN_2184257 := 0
ERRATA_KLEIN_BOOKER := 0
ERRATA_MTH_BOOKER := 0
ERRATA_MTHELP_BOOKER := 0
CRASH_REPORTING := 1
CONFIG_MTK_BL31_RAMDUMP := 0
endif
ifeq ($(BUILD_TYPE),debug)
MTK_PTP3_PROC_DEBUG := 1
MTK_SRAMRC_DEBUG := 1
MTK_IOMMU_DEBUG := 1
MTK_DCM_DEBUG := 1
MTK_EMI_MPU_DEBUG := 1
endif
ifeq (${SPD},none)
SPD_NONE:=1
$(eval $(call add_define,SPD_NONE))
endif
# TEE OS config
ifeq ($(SPD), tbase)
CONFIG_TBASE := y
endif
# MICROTRUST OS config
ifeq ($(SPD), teeid)
CONFIG_MICROTRUST_TEEI := y
endif
ifeq (${CONFIG_ARCH_ARM_V8_2},y)
ARCH_VERSION := armv8_2
endif
ifeq (${CONFIG_ARCH_ARM_V9},y)
ARCH_VERSION := armv9
endif
@@ -0,0 +1,142 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Get local directory path
define GET_LOCAL_DIR
$(patsubst %/,%,$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))))
endef
# Clear module source variable
define CLEAR_LOCAL_SRCS
$(eval $(1) :=)
endef
define EXPAND_SUB_MAKEFILE
include $(S)
endef
# Expand sub rules.mk
define INCLUDE_MAKEFILE
$(eval MODULES_SUB_MAKEFILE := $(patsubst %,%/rules.mk,$(1)))
$(foreach S,$(MODULES_SUB_MAKEFILE),$(eval $(EXPAND_SUB_MAKEFILE)))
endef
# Determine option variable is defined or not then define it
define add_defined_option
ifdef $(1)
ifeq ($(findstring $(value $(1)), $(uppercase_table)),)
DEFINES += -D$(1)$(if $(value $(1)),=$(value $(1)),)
else
ifeq ($(strip $(value $(1))),y)
DEFINES += -D$(1)$(if $(value $(1)),=1,)
endif
endif
endif
endef
define EXPAND_RULES_MAKEFILE
LOCAL_SRCS-y :=
MODULE :=
SUB_RULES-y :=
include $(S)
endef
# INCLUDE_MODULES macro expand included modules rules.mk
# Arguments:
# $(1) = MODULES variables
define INCLUDE_MODULES
$(eval MODULES_TEMP := $(1))
$(eval MODULES_MAKEFILE := $(patsubst %,%/rules.mk,$(MODULES_TEMP)))
$(foreach S,$(MODULES_MAKEFILE),$(eval $(EXPAND_RULES_MAKEFILE)))
endef
# MAKE_LOCALS expand module source file variable to BL${BL}_SOURCES
# Arguments:
# $(1) = source file
# $(2) = BL stage (1, 2, 2u, 31, 32)
define MAKE_LOCALS
$(eval $(call uppercase,$(2))_SOURCES += $(1))
endef
# MAKE_LINKERFILE change linker script source file name to
# target linker script
# $(1) = linker script source file
# $(2) = BL stage
define MAKE_LINKERFILE
$(eval EXTRA_GENERATED_LINKER_SCRIPT += $(BUILD_PLAT)/$(2)/$(patsubst %.ld.S,%.ld,$(notdir $(1))))
endef
# MAKE_LINKERFILE_ITER call MAKE_LINKERFILE iteratively
# $(1) = linker script source file
# $(2) = BL stage
define MAKE_LINKERFILE_ITER
$(eval $(foreach link_src,$(1),$(call MAKE_LINKERFILE,$(link_src),$(2))))
endef
# MAKE_LD_ITER generate the linker scripts using the C preprocessor iteratively
# $(1) = output linker script
# $(2) = input template
# $(3) = BL stage (1, 2, 2u, 31, 32)
define MAKE_LD_ITER
$(eval index_list=$(shell seq $(words $(1))))
$(eval $(foreach i, $(index_list), \
$(call MAKE_LD,$(word $(i), $(1)), $(word $(i), $(2)),$(3))))
endef
# MAKE_MODULE reference MAKE_OBJS.
# Create module folder under out/bl$(BL)/$(module)
# Arguments:
# $(1) = module name
# $(2) = source file
# $(3) = BL stage
define MAKE_MODULE
$(eval MODULE := $(strip $(1)))
$(eval BUILD_DIR := ${BUILD_PLAT}/${3})
$(eval SOURCES := $(2))
$(eval OBJS_TEMP := $(addprefix $(BUILD_DIR)/$(MODULE)/,$(call SOURCES_TO_OBJS,$(SOURCES))))
$(eval MODULE_OBJS += $(OBJS_TEMP))
# We use sort only to get a list of unique object directory names.
# ordering is not relevant but sort removes duplicates.
$(eval TEMP_OBJ_DIRS := $(sort $(dir ${OBJS_TEMP} ${LINKERFILE})))
# The $(dir ) function leaves a trailing / on the directory names
# Rip off the / to match directory names with make rule targets.
$(eval OBJ_DIRS := $(patsubst %/,%,$(TEMP_OBJ_DIRS)))
$(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
${3}_dirs: | ${OBJ_DIRS}
$(eval $(call MAKE_OBJS,$(BUILD_DIR)/$(MODULE),$(SOURCES),${3}))
libraries: $(OBJS_TEMP)
endef
# Include MTK configuration files
# MTK makefile variables
ifeq (${COREBOOT},1)
MTK_COMMON_CFG := $(MTK_PLAT)/common/coreboot_config.mk
else
MTK_COMMON_CFG := $(MTK_PLAT)/common/common_config.mk
endif
MTK_PLAT := plat/mediatek
MTK_PLAT_SOC := ${MTK_PLAT}/${MTK_SOC}
MTK_PLAT_CFG := $(MTK_PLAT_SOC)/plat_config.mk
MTK_PROJECT_CFG := $(MTK_PLAT)/project/$(PLAT)/project_config.mk
MTK_OPTIONS := $(MTK_PLAT)/build_helpers/options.mk
MTK_COND_EVAL := $(MTK_PLAT)/build_helpers/conditional_eval_options.mk
# Indicate which BL should be built in command line
ifeq (${NEED_BL32},yes)
MTK_BL := bl32
else
MTK_BL := bl31
endif
# Include common, platform, board level config
include $(MTK_COMMON_CFG)
include $(MTK_PLAT_CFG)
-include $(MTK_PROJECT_CFG)
include $(MTK_COND_EVAL)
include $(MTK_OPTIONS)
@@ -0,0 +1,30 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Expand include modules
$(eval $(call INCLUDE_MODULES,$(MODULES-y)))
# Make next section align to page size
ifneq ($(MTK_EXTRA_LINKERFILE),)
$(eval $(call MAKE_LINKERFILE_ITER,$(MTK_LINKERFILE_SOURCE),bl31))
# EXTRA_GENERATED_LINKER_SCRIPT is a global variable of derived linker
# script list(from MTK_LINKERFILE_SOURCE) after MAKE_LINKERFILE_ITER
# function call
EXTRA_LINKERFILE += ${EXTRA_GENERATED_LINKER_SCRIPT}
# Expand derived linker script as build target
$(eval $(call MAKE_LD_ITER, $(EXTRA_GENERATED_LINKER_SCRIPT),$(MTK_LINKERFILE_SOURCE),bl31))
# mtk_align.ld MUST BE THE LAST LINKER SCRIPT!
EXTRA_LINKERFILE += ${MTK_PLAT}/include/mtk_align.ld
# bl31.ld should depend on EXTRA_LINKERFILE
$(eval ${BUILD_PLAT}/bl31/bl31.ld: ${EXTRA_LINKERFILE})
EXTRA_LINKERFILE := $(addprefix -T,$(EXTRA_LINKERFILE))
else
EXTRA_LINKERFILE :=
endif
@@ -0,0 +1,25 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# call add_defined_option to evaluate MTK defined value
$(eval $(call add_defined_option,MTK_SIP_KERNEL_BOOT_ENABLE))
$(eval $(call add_defined_option,PLAT_EXTRA_RODATA_INCLUDES))
$(eval $(call add_defined_option,MTK_EXTRA_LINKERFILE))
$(eval $(call add_defined_option,MTK_BL31_AS_BL2))
$(eval $(call add_defined_option,MTK_BL33_IS_64BIT))
$(eval $(call add_defined_option,PLAT_XLAT_TABLES_DYNAMIC))
$(eval $(call add_defined_option,MTK_ADAPTED))
$(eval $(call add_defined_option,MTK_PUBEVENT_ENABLE))
$(eval $(call add_defined_option,MTK_SOC))
$(eval $(call add_defined_option,UART_CLOCK))
$(eval $(call add_defined_option,UART_BAUDRATE))
$(eval $(call add_defined_option,CONFIG_MTK_MCUSYS))
$(eval $(call add_defined_option,CONFIG_MTK_PM_SUPPORT))
$(eval $(call add_defined_option,CONFIG_MTK_CPU_PM_SUPPORT))
$(eval $(call add_defined_option,CONFIG_MTK_SMP_EN))
$(eval $(call add_defined_option,CONFIG_MTK_CPU_SUSPEND_EN))
$(eval $(call add_defined_option,CONFIG_MTK_PM_ARCH))
$(eval $(call add_defined_option,CONFIG_MTK_CPU_PM_ARCH))
@@ -0,0 +1,34 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# indicate the reset vector address can be programmed
PROGRAMMABLE_RESET_ADDRESS := 1
MULTI_CONSOLE_API := 1
COLD_BOOT_SINGLE_CPU := 1
# Build flag to include AArch32 registers in cpu context save and restore during
# world switch. This flag must be set to 0 for AArch64-only platforms.
CTX_INCLUDE_AARCH32_REGS := 0
PLAT_XLAT_TABLES_DYNAMIC := 1
# enable this definition to print irq dump status in tf-a
GIC_DEBUG := 0
# Enable stack protector.
# Allowed values are "all", "strong", "default" and "none"
ENABLE_STACK_PROTECTOR := strong
# AMU, Kernel will access amuserenr_el0 if PE supported
# Firmware _must_ implement AMU support
ENABLE_AMU := 1
VENDOR_EXTEND_PUBEVENT_ENABLE := 1
# MTK define options
MTK_BL33_IS_64BIT := 0
MTK_ADAPTED := 1
# MTK module config
CONFIG_MTK_INTERRUPT := y
CONFIG_MTK_UART := y
# UART baudrate
UART_BAUDRATE := 921600
@@ -0,0 +1,15 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# indicate the reset vector address can be programmed
PROGRAMMABLE_RESET_ADDRESS := 1
COLD_BOOT_SINGLE_CPU := 1
# Build flag to include AArch32 registers in cpu context save and restore during
# world switch. This flag must be set to 0 for AArch64-only platforms.
CTX_INCLUDE_AARCH32_REGS := 0
PLAT_XLAT_TABLES_DYNAMIC := 1
VENDOR_EXTEND_PUBEVENT_ENABLE := 1
@@ -0,0 +1,110 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mt_lp_rm.h>
#include <stddef.h>
struct platform_mt_resource_manager {
unsigned int count;
struct mt_resource_manager *plat_rm;
};
static struct platform_mt_resource_manager plat_mt_rm;
int mt_lp_rm_register(struct mt_resource_manager *rm)
{
unsigned int i;
struct mt_resource_constraint *const *rc;
if ((rm == NULL) || (rm->consts == NULL) ||
(plat_mt_rm.plat_rm != NULL)) {
return MT_RM_STATUS_BAD;
}
for (i = 0U, rc = rm->consts; *rc != NULL; i++, rc++) {
if ((*rc)->init != NULL) {
(*rc)->init();
}
}
plat_mt_rm.plat_rm = rm;
plat_mt_rm.count = i;
return MT_RM_STATUS_OK;
}
int mt_lp_rm_reset_constraint(int idx, unsigned int cpuid, int stateid)
{
struct mt_resource_constraint const *rc = NULL;
if ((plat_mt_rm.plat_rm == NULL) || (idx < 0) ||
(idx >= plat_mt_rm.count)) {
return MT_RM_STATUS_BAD;
}
rc = plat_mt_rm.plat_rm->consts[idx];
if ((rc == NULL) || (rc->reset == NULL)) {
return MT_RM_STATUS_BAD;
}
return rc->reset(cpuid, stateid);
}
int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
int stateid, void *priv)
{
int i, res = MT_RM_STATUS_BAD;
struct mt_resource_constraint *const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if ((rm == NULL) || (idx < 0) || (idx >= plat_mt_rm.count)) {
return res;
}
/* If subsys clk/mtcmos is on, add block-resource-off flag */
if (rm->update != NULL) {
res = rm->update(rm->consts, stateid, priv);
if (res != 0) {
return res;
}
}
for (i = idx, rc = (rm->consts + idx); *rc != NULL; i++, rc++) {
if (((*rc)->is_valid != NULL) &&
((*rc)->is_valid(cpuid, stateid))) {
if (((*rc)->run != NULL) &&
((*rc)->run(cpuid, stateid) == 0)) {
res = i;
break;
}
}
}
return res;
}
int mt_lp_rm_do_update(int stateid, int type, void const *p)
{
int res = MT_RM_STATUS_BAD;
struct mt_resource_constraint *const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if (rm == NULL) {
return res;
}
for (rc = rm->consts; *rc != NULL; rc++) {
if ((*rc)->update != NULL) {
res = (*rc)->update(stateid, type, p);
if (res != MT_RM_STATUS_OK) {
break;
}
}
}
return res;
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_LP_RM_H
#define MT_LP_RM_H
#include <stdbool.h>
#define MT_RM_STATUS_OK 0
#define MT_RM_STATUS_BAD -1
enum PLAT_MT_LPM_RC_TYPE {
PLAT_RC_UPDATE_CONDITION,
PLAT_RC_UPDATE_REMAIN_IRQS
};
struct mt_resource_constraint {
int level;
int (*init)(void);
bool (*is_valid)(unsigned int cpu, int stateid);
int (*update)(int stateid, int type, const void *p);
int (*run)(unsigned int cpu, int stateid);
int (*reset)(unsigned int cpu, int stateid);
unsigned int (*allow)(int stateid);
};
struct mt_resource_manager {
int (*update)(struct mt_resource_constraint **con,
int stateid, void *priv);
struct mt_resource_constraint **consts;
};
extern int mt_lp_rm_register(struct mt_resource_manager *rm);
extern int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
int stateid, void *priv);
extern int mt_lp_rm_reset_constraint(int constraint_id, unsigned int cpuid,
int stateid);
extern int mt_lp_rm_do_update(int stateid, int type, void const *p);
#endif /* MT_LP_RM_H */
@@ -0,0 +1,14 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := lpm
LOCAL_SRCS-y := $(LOCAL_DIR)/mt_lp_rm.c
PLAT_INCLUDES += -I${LOCAL_DIR}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/generic_delay_timer.h>
#if XLAT_TABLES_LIB_V2 && PLAT_XLAT_TABLES_DYNAMIC
#include <lib/xlat_tables/xlat_tables_v2.h>
#endif
#include <plat/common/platform.h>
#if COREBOOT
#include <common/desc_image_load.h>
#include <drivers/ti/uart/uart_16550.h>
#include <lib/coreboot.h>
#include <plat_params.h>
#endif
/* MTK headers */
#if MTK_SIP_KERNEL_BOOT_ENABLE
#include <cold_boot.h>
#endif
#include <lib/mtk_init/mtk_init.h>
#include <mtk_mmap_pool.h>
IMPORT_SYM(uintptr_t, __RW_START__, RW_START);
IMPORT_SYM(uintptr_t, __DATA_START__, DATA_START);
#if COREBOOT
static entry_point_info_t bl32_ep_info;
static entry_point_info_t bl33_ep_info;
/*******************************************************************************
* Return a pointer to the 'entry_point_info' structure of the next image for
* the security state specified. BL33 corresponds to the non-secure image type
* while BL32 corresponds to the secure image type. A NULL pointer is returned
* if the image does not exist.
******************************************************************************/
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
entry_point_info_t *next_image_info;
next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
assert(next_image_info->h.type == PARAM_EP);
/* None of the images on this platform can have 0x0 as the entrypoint */
if (next_image_info->pc) {
return next_image_info;
} else {
return NULL;
}
}
#else
#ifndef MTK_BL31_AS_BL2
static struct mtk_bl31_fw_config bl31_fw_config;
#else
struct mtk_bl31_fw_config bl31_fw_config;
#endif
/* In order to be accessed after MMU enable */
static struct mtk_bl_param_t bl_param_clone;
void *get_mtk_bl31_fw_config(int index)
{
void *arg = NULL;
switch (index) {
case BOOT_ARG_FROM_BL2:
arg = bl31_fw_config.from_bl2;
break;
case BOOT_ARG_SOC_FW_CONFIG:
arg = bl31_fw_config.soc_fw_config;
break;
case BOOT_ARG_HW_CONFIG:
arg = bl31_fw_config.hw_config;
break;
case BOOT_ARG_RESERVED:
arg = bl31_fw_config.reserved;
break;
default:
WARN("Fail to get boot arg, index:%d", index);
break;
}
return arg;
}
#endif
/*****************************************************************************
* Perform the very early platform specific architectural setup shared between
* ARM standard platforms. This only does basic initialization. Later
* architectural setup (bl31_arch_setup()) does not do anything platform
* specific.
******************************************************************************/
void bl31_early_platform_setup2(u_register_t from_bl2,
u_register_t soc_fw_config,
u_register_t hw_config, u_register_t plat_params_from_bl2)
{
#if COREBOOT
static console_t console;
params_early_setup(soc_fw_config);
if (coreboot_serial.type) {
console_16550_register(coreboot_serial.baseaddr,
coreboot_serial.input_hertz,
coreboot_serial.baud,
&console);
}
bl31_params_parse_helper(from_bl2, &bl32_ep_info, &bl33_ep_info);
#else
struct mtk_bl_param_t *p_mtk_bl_param = (struct mtk_bl_param_t *)from_bl2;
if (p_mtk_bl_param == NULL) {
ERROR("from_bl2 should not be NULL\n");
panic();
}
memcpy(&bl_param_clone, p_mtk_bl_param, sizeof(struct mtk_bl_param_t));
bl31_fw_config.from_bl2 = (void *)&bl_param_clone;
bl31_fw_config.soc_fw_config = (void *)soc_fw_config;
bl31_fw_config.hw_config = (void *)hw_config;
bl31_fw_config.reserved = (void *)plat_params_from_bl2;
#endif
INFO("MTK BL31 start\n");
/* Init delay function */
generic_delay_timer_init();
/* Initialize module initcall */
mtk_init_one_level(MTK_INIT_LVL_EARLY_PLAT);
}
void bl31_plat_arch_setup(void)
{
const mmap_region_t bl_regions[] = {
MAP_BL_RO,
MAP_BL_RW,
#if USE_COHERENT_MEM
MAP_BL_COHERENT_RAM,
#endif
{0},
};
mtk_xlat_init(bl_regions);
/* Initialize module initcall */
mtk_init_one_level(MTK_INIT_LVL_ARCH);
}
/*****************************************************************************
* Perform any BL31 platform setup common to ARM standard platforms
******************************************************************************/
void bl31_platform_setup(void)
{
mtk_init_one_level(MTK_INIT_LVL_PLAT_SETUP_0);
mtk_init_one_level(MTK_INIT_LVL_PLAT_SETUP_1);
}
/*******************************************************************************
* Operations before cold CPU leave BL31.
* Switch console to runtime state.
******************************************************************************/
void bl31_plat_runtime_setup(void)
{
mtk_init_one_level(MTK_INIT_LVL_PLAT_RUNTIME);
console_switch_state(CONSOLE_FLAG_RUNTIME);
}
unsigned int plat_get_syscnt_freq2(void)
{
return SYS_COUNTER_FREQ_IN_HZ;
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/arm/cci.h>
#include <drivers/console.h>
#include <lib/mmio.h>
#include <lib/smccc.h>
#include <lib/xlat_tables/xlat_tables.h>
#include <plat/common/platform.h>
#include <services/arm_arch_svc.h>
#include <mtk_plat_common.h>
#include <mtk_sip_svc.h>
#include <plat_private.h>
void clean_top_32b_of_param(uint32_t smc_fid,
u_register_t *px1,
u_register_t *px2,
u_register_t *px3,
u_register_t *px4)
{
/* if parameters from SMC32. Clean top 32 bits */
if (GET_SMC_CC(smc_fid) == SMC_64) {
*px1 = *px1 & SMC32_PARAM_MASK;
*px2 = *px2 & SMC32_PARAM_MASK;
*px3 = *px3 & SMC32_PARAM_MASK;
*px4 = *px4 & SMC32_PARAM_MASK;
}
}
/*****************************************************************************
* plat_is_smccc_feature_available() - This function checks whether SMCCC
* feature is availabile for platform.
* @fid: SMCCC function id
*
* Return SMC_OK if SMCCC feature is available and SMC_ARCH_CALL_NOT_SUPPORTED
* otherwise.
*****************************************************************************/
int32_t plat_is_smccc_feature_available(u_register_t fid)
{
switch (fid) {
case SMCCC_ARCH_SOC_ID:
return SMC_ARCH_CALL_SUCCESS;
default:
return SMC_ARCH_CALL_NOT_SUPPORTED;
}
}
int32_t plat_get_soc_version(void)
{
uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_MTK_BKID, JEDEC_MTK_MFID);
return (int32_t)(manfid | (SOC_CHIP_ID & SOC_ID_IMPL_DEF_MASK));
}
int32_t plat_get_soc_revision(void)
{
return 0;
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MTK_PLAT_COMMON_H
#define MTK_PLAT_COMMON_H
#include <stdint.h>
#include <common/bl_common.h>
#include <common/param_header.h>
/*******************************************************************************
* Function and variable prototypes
******************************************************************************/
#define SMC32_PARAM_MASK (0xFFFFFFFF)
#define JEDEC_MTK_BKID U(4)
#define JEDEC_MTK_MFID U(0x26)
struct mtk_bl31_params {
param_header_t h;
image_info_t *bl31_image_info;
entry_point_info_t *bl32_ep_info;
image_info_t *bl32_image_info;
entry_point_info_t *bl33_ep_info;
image_info_t *bl33_image_info;
};
/* Declarations for mtk_plat_common.c */
uint32_t plat_get_spsr_for_bl32_entry(void);
uint32_t plat_get_spsr_for_bl33_entry(void);
void clean_top_32b_of_param(uint32_t smc_fid, u_register_t *x1,
u_register_t *x2,
u_register_t *x3,
u_register_t *x4);
void bl31_prepare_kernel_entry(uint64_t k32_64);
void enable_ns_access_to_cpuectlr(void);
void boot_to_kernel(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
uint64_t get_kernel_info_pc(void);
uint64_t get_kernel_info_r0(void);
uint64_t get_kernel_info_r1(void);
uint64_t get_kernel_info_r2(void);
extern struct atf_arg_t gteearg;
#endif /* MTK_PLAT_COMMON_H */
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <drivers/console.h>
#include <lib/mmio.h>
#include <tools_share/uuid.h>
#include <mtk_plat_common.h>
#include <mtk_sip_svc.h>
#include <plat_sip_calls.h>
/* Mediatek SiP Service UUID */
DEFINE_SVC_UUID2(mtk_sip_svc_uid,
0xa42b58f7, 0x6242, 0x7d4d, 0x80, 0xe5,
0x8f, 0x95, 0x05, 0x00, 0x0f, 0x3d);
#pragma weak mediatek_plat_sip_handler
uintptr_t mediatek_plat_sip_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
SMC_RET1(handle, SMC_UNK);
}
/*
* This function handles Mediatek defined SiP Calls */
uintptr_t mediatek_sip_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uint32_t ns;
/* if parameter is sent from SMC32. Clean top 32 bits */
clean_top_32b_of_param(smc_fid, &x1, &x2, &x3, &x4);
/* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags);
if (!ns) {
/* SiP SMC service secure world's call */
;
} else {
/* SiP SMC service normal world's call */
switch (smc_fid) {
#if MTK_SIP_SET_AUTHORIZED_SECURE_REG_ENABLE
case MTK_SIP_SET_AUTHORIZED_SECURE_REG: {
/* only use ret here */
uint64_t ret;
ret = mt_sip_set_authorized_sreg((uint32_t)x1,
(uint32_t)x2);
SMC_RET1(handle, ret);
}
#endif
#if MTK_SIP_KERNEL_BOOT_ENABLE
case MTK_SIP_KERNEL_BOOT_AARCH32:
boot_to_kernel(x1, x2, x3, x4);
SMC_RET0(handle);
#endif
default:
/* Do nothing in default case */
break;
}
}
return mediatek_plat_sip_handler(smc_fid, x1, x2, x3, x4,
cookie, handle, flags);
}
/*
* This function is responsible for handling all SiP calls from the NS world
*/
uintptr_t sip_smc_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
switch (smc_fid) {
case SIP_SVC_CALL_COUNT:
/* Return the number of Mediatek SiP Service Calls. */
SMC_RET1(handle,
MTK_COMMON_SIP_NUM_CALLS + MTK_PLAT_SIP_NUM_CALLS);
case SIP_SVC_UID:
/* Return UID to the caller */
SMC_UUID_RET(handle, mtk_sip_svc_uid);
case SIP_SVC_VERSION:
/* Return the version of current implementation */
SMC_RET2(handle, MTK_SIP_SVC_VERSION_MAJOR,
MTK_SIP_SVC_VERSION_MINOR);
default:
return mediatek_sip_handler(smc_fid, x1, x2, x3, x4,
cookie, handle, flags);
}
}
/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
mediatek_sip_svc,
OEN_SIP_START,
OEN_SIP_END,
SMC_TYPE_FAST,
NULL,
sip_smc_handler
);
@@ -0,0 +1,235 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#if MTK_SIP_KERNEL_BOOT_ENABLE
#include <cold_boot.h>
#endif
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <lib/mtk_init/mtk_init.h>
#include <mtk_sip_svc.h>
#define SMC_HANDLER_DEBUG(...) VERBOSE(__VA_ARGS__)
#define SMC_HANDLER_DEBUG_NOT_IMP_MSG "%s[0x%x] smc handler not implemented\n"
#define SMC_HANDLER_DEBUG_START_MSG "%s[0x%x] smc handler start, smc desc. index:%d\n"
#define SMC_HANDLER_DEBUG_END_MSG "%s[0x%x] smc handler end\n"
/*
* These macros below are used to identify SIP calls from Kernel,
* Hypervisor, or 2ndBootloader
*/
#define SIP_FID_ORI_MASK (0xc000)
#define SIP_FID_ORI_SHIFT (14)
#define SIP_FID_KERNEL (0x0)
#define SIP_FID_KERNEL_VIA_GZ (0x1)
#define SIP_FID_GZ (0x2)
#define GET_SMC_ORI(_fid) (((_fid) & SIP_FID_ORI_MASK) >> SIP_FID_ORI_SHIFT)
#define GET_SMC_ORI_NUM(_fid) ((_fid) & ~(SIP_FID_ORI_MASK))
#define is_from_nsel2(_ori) (_ori == SIP_FID_GZ)
#define is_from_bl33(_ori) \
((_ori != SIP_FID_GZ) && (is_el1_2nd_bootloader() == 1))
#define is_from_nsel1(_ori) \
(((_ori == SIP_FID_KERNEL) || \
(_ori == SIP_FID_KERNEL_VIA_GZ)) && \
(is_el1_2nd_bootloader() == 0))
#define is_smc_forbidden(_ori) (_ori == SIP_FID_KERNEL_VIA_GZ)
#define MASK_32_BIT (0xffffffffU)
#define SMC_ID_EXPAND_AS_SMC_OPERATION(_smc_id, _smc_num) \
case _smc_id##_AARCH32: \
{ \
x1 = x1 & MASK_32_BIT; \
x2 = x2 & MASK_32_BIT; \
x3 = x3 & MASK_32_BIT; \
x4 = x4 & MASK_32_BIT; \
} \
case _smc_id##_AARCH64: \
{ \
if (_smc_id##_descriptor_index < 0) { \
SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_NOT_IMP_MSG, #_smc_id, smc_id); \
break; \
} \
if (_smc_id##_descriptor_index >= smc_id_descriptor_max) { \
SMC_HANDLER_DEBUG("smc descriptor index[%d] exceed max[%d]\n", \
_smc_id##_descriptor_index, smc_id_descriptor_max); \
break; \
} \
SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_START_MSG, #_smc_id, smc_id, \
_smc_id##_descriptor_index); \
ret = smc_handler_pool[_smc_id##_descriptor_index].smc_handler(x1,\
x2, x3, x4, handle, &smc_ret); \
SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_END_MSG, #_smc_id, smc_id); \
break; \
}
#define SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX(_smc_id, _smc_num) \
short _smc_id##_descriptor_index __section("mtk_plat_ro") = -1;
MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX);
MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX);
IMPORT_SYM(uintptr_t, __MTK_SMC_POOL_START__, MTK_SMC_POOL_START);
IMPORT_SYM(uintptr_t, __MTK_SMC_POOL_END_UNALIGNED__, MTK_SMC_POOL_END_UNALIGNED);
static const struct smc_descriptor *smc_handler_pool;
static short smc_id_descriptor_max;
#if !MTK_SIP_KERNEL_BOOT_ENABLE
/*
* If there is no SMC request needs to be served in 2nd bootloader,
* disable the service path inherently.
*/
bool is_el1_2nd_bootloader(void)
{
return false;
}
#endif
static void print_smc_descriptor(const struct smc_descriptor pool[])
{
const struct smc_descriptor *p_smc_desc;
INFO("print smc descriptor pool\n");
for (p_smc_desc = &pool[0];
(char *)p_smc_desc < (char *)MTK_SMC_POOL_END_UNALIGNED;
p_smc_desc++) {
INFO("descriptor name:%s\n", p_smc_desc->smc_name);
INFO("descriptor index:%d\n", *p_smc_desc->smc_descriptor_index);
INFO("smc id 32:0x%x, smc id 64:0x%x\n",
p_smc_desc->smc_id_aarch32, p_smc_desc->smc_id_aarch64);
}
}
static int mtk_smc_handler_init(void)
{
const struct smc_descriptor *iter;
short index_cnt;
int ret = 0;
smc_handler_pool = (const struct smc_descriptor *)MTK_SMC_POOL_START;
/* Designate descriptor index point to smc_handler_pool */
for (index_cnt = 0, iter = &smc_handler_pool[0];
(char *)iter < (char *)MTK_SMC_POOL_END_UNALIGNED;
iter++, index_cnt++) {
if (index_cnt < 0) {
SMC_HANDLER_DEBUG("smc handler pool index overflow!\n");
ret = -EPERM;
assert(0);
break;
}
*(iter->smc_descriptor_index) = index_cnt;
}
smc_id_descriptor_max = index_cnt;
print_smc_descriptor(smc_handler_pool);
return ret;
}
MTK_EARLY_PLAT_INIT(mtk_smc_handler_init);
/* This function handles Mediatek defined SiP Calls from Bootloader */
static uintptr_t mtk_smc_handler_bl33(uint32_t smc_id,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uintptr_t ret = MTK_SIP_E_SUCCESS;
struct smccc_res smc_ret = {0};
switch (smc_id) {
MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION);
default:
INFO("BL33 SMC ID:0x%x not supported\n", smc_id);
ret = SMC_UNK;
break;
}
SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3);
}
/* This function handles Mediatek defined SiP Calls from Kernel */
static uintptr_t mtk_smc_handler_nsel1(uint32_t smc_id,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uintptr_t ret = MTK_SIP_E_SUCCESS;
struct smccc_res smc_ret = {0};
switch (smc_id) {
MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION);
default:
INFO("NSEL1 SMC ID:0x%x not supported\n", smc_id);
ret = SMC_UNK;
break;
}
SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3);
}
static uintptr_t mtk_smc_handler(uint32_t smc_id,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uintptr_t ret = SMC_UNK;
uint32_t ns;
uint32_t smc_ori;
uint32_t smc_num;
/* Get SMC Originator bit 14.15 */
smc_ori = GET_SMC_ORI(smc_id);
/* Get SMC Number. Clean bit 14.15 */
smc_num = GET_SMC_ORI_NUM(smc_id);
/* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags);
if (ns && is_smc_forbidden(smc_ori)) {
ERROR("%s: Forbidden SMC call (0x%x)\n", __func__, smc_id);
SMC_RET1(handle, ret);
}
if (!ns) {
/* SiP SMC service secure world's call */
INFO("Secure SMC ID:0x%x not supported\n", smc_id);
SMC_RET1(handle, ret);
}
if (is_from_bl33(smc_ori)) {
/* SiP SMC service secure bootloader's call */
return mtk_smc_handler_bl33(smc_num, x1, x2, x3, x4,
cookie, handle, flags);
} else if (is_from_nsel1(smc_ori)) {
/* SiP SMC service kernel's call */
return mtk_smc_handler_nsel1(smc_num, x1, x2, x3, x4,
cookie, handle, flags);
}
INFO("SMC ID:0x%x not supported\n", smc_id);
SMC_RET1(handle, ret);
}
/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
mtk_smc_handler,
OEN_SIP_START,
OEN_SIP_END,
SMC_TYPE_FAST,
NULL,
mtk_smc_handler
);
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/bl_aux_params/bl_aux_params.h>
#include <common/debug.h>
#include <plat_params.h>
#include <string.h>
static struct bl_aux_gpio_info rst_gpio;
struct bl_aux_gpio_info *plat_get_mtk_gpio_reset(void)
{
return &rst_gpio;
}
static bool mtk_aux_param_handler(struct bl_aux_param_header *param)
{
/* Store platform parameters for later processing if needed. */
switch (param->type) {
case BL_AUX_PARAM_MTK_RESET_GPIO:
rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
return true;
}
return false;
}
void params_early_setup(u_register_t plat_param_from_bl2)
{
bl_aux_params_parse(plat_param_from_bl2, mtk_aux_param_handler);
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2019, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLAT_PARAMS_H
#define PLAT_PARAMS_H
#include <stdint.h>
#include <export/plat/mediatek/common/plat_params_exp.h>
struct bl_aux_gpio_info *plat_get_mtk_gpio_reset(void);
void params_early_setup(u_register_t plat_param_from_bl2);
#endif
@@ -0,0 +1,15 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mtk_common
LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_bl31_setup.c
LOCAL_SRCS-y += ${LOCAL_DIR}/mtk_smc_handlers.c
LOCAL_SRCS-$(MTK_SIP_KERNEL_BOOT_ENABLE) += ${LOCAL_DIR}/cold_boot.c
$(eval $(call MAKE_LOCALS,$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <stdbool.h>
#include <common/debug.h>
#include <audio.h>
#include <mtk_sip_svc.h>
#define MODULE_TAG "[AUDIO]"
static u_register_t audio_smc_handler(u_register_t x1, u_register_t x2,
u_register_t x3, u_register_t x4,
void *handle, struct smccc_res *smccc_ret)
{
uint32_t request_ops;
int ret;
request_ops = (uint32_t)x1;
switch (request_ops) {
case MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS:
ret = set_audio_domain_sidebands();
break;
default:
ERROR("%s: %s: Unsupported request_ops %x\n",
MODULE_TAG, __func__, request_ops);
ret = -EIO;
break;
}
VERBOSE("%s: %s, request_ops = %x, ret = %d\n",
MODULE_TAG, __func__, request_ops, ret);
return ret;
}
/* Register SiP SMC service */
DECLARE_SMC_HANDLER(MTK_SIP_AUDIO_CONTROL, audio_smc_handler);
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef AUDIO_H
#define AUDIO_H
#include <stdint.h>
#include <lib/mmio.h>
enum mtk_audio_smc_call_op {
MTK_AUDIO_SMC_OP_INIT = 0,
MTK_AUDIO_SMC_OP_DRAM_REQUEST,
MTK_AUDIO_SMC_OP_DRAM_RELEASE,
MTK_AUDIO_SMC_OP_SRAM_REQUEST,
MTK_AUDIO_SMC_OP_SRAM_RELEASE,
MTK_AUDIO_SMC_OP_ADSP_REQUEST,
MTK_AUDIO_SMC_OP_ADSP_RELEASE,
MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS,
MTK_AUDIO_SMC_OP_BTCVSD_WRITE,
MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_CLEAR,
MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_UNDERFLOW,
MTK_AUDIO_SMC_OP_NUM,
};
int32_t set_audio_domain_sidebands(void);
#endif /* AUDIO_H */
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2022, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <audio.h>
#include <mt_audio_private.h>
#include <mtk_mmap_pool.h>
#include <platform_def.h>
#include <spm_reg.h>
#define MODULE_TAG "[AUDIO_DOMAIN]"
int32_t set_audio_domain_sidebands(void)
{
uint32_t val = mmio_read_32(PWR_STATUS);
if ((val & BIT(SPM_PWR_STATUS_AUDIO_BIT)) == 0) {
ERROR("%s: %s, pwr_status=0x%x, w/o [%d]AUDIO!\n",
MODULE_TAG, __func__, val, SPM_PWR_STATUS_AUDIO_BIT);
return -EIO;
}
mmio_write_32(AFE_SE_SECURE_CON, 0x0);
mmio_write_32(AFE_SECURE_SIDEBAND0, 0x0);
mmio_write_32(AFE_SECURE_SIDEBAND1, 0x0);
mmio_write_32(AFE_SECURE_SIDEBAND2, 0x0);
mmio_write_32(AFE_SECURE_SIDEBAND3, 0x0);
VERBOSE("%s: %s, SE_SECURE_CON=0x%x, SIDEBAND0/1/2/3=0x%x/0x%x/0x%x/0x%x\n",
MODULE_TAG, __func__,
mmio_read_32(AFE_SE_SECURE_CON),
mmio_read_32(AFE_SECURE_SIDEBAND0),
mmio_read_32(AFE_SECURE_SIDEBAND1),
mmio_read_32(AFE_SECURE_SIDEBAND2),
mmio_read_32(AFE_SECURE_SIDEBAND3));
return 0;
}
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_AUDIO_PRIVATE_H
#define MT_AUDIO_PRIVATE_H
#include <platform_def.h>
#define AFE_SE_SECURE_CON (AUDIO_BASE + 0x17a8)
#define AFE_SECURE_SIDEBAND0 (AUDIO_BASE + 0x1908)
#define AFE_SECURE_SIDEBAND1 (AUDIO_BASE + 0x190c)
#define AFE_SECURE_SIDEBAND2 (AUDIO_BASE + 0x1910)
#define AFE_SECURE_SIDEBAND3 (AUDIO_BASE + 0x1914)
#define SPM_PWR_STATUS_AUDIO_BIT (6)
#endif /* MT_AUDIO_PRIVATE_H */
@@ -0,0 +1,13 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := audio_${MTK_SOC}
LOCAL_SRCS-y := ${LOCAL_DIR}/audio_domain.c
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,19 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := audio
LOCAL_SRCS-y := ${LOCAL_DIR}/audio.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
SUB_RULES-y:= ${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
@@ -0,0 +1,549 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gic_common.h>
#include <lib/mmio.h>
#include <mt_cirq.h>
#include <mt_gic_v3.h>
static struct cirq_events cirq_all_events = {
.spi_start = CIRQ_SPI_START,
};
static uint32_t already_cloned;
/*
* mt_irq_mask_restore: restore all interrupts
* @mask: pointer to struct mtk_irq_mask for storing the original mask value.
* Return 0 for success; return negative values for failure.
* (This is ONLY used for the idle current measurement by the factory mode.)
*/
int mt_irq_mask_restore(struct mtk_irq_mask *mask)
{
if (mask == NULL) {
return -1;
}
if (mask->header != IRQ_MASK_HEADER) {
return -1;
}
if (mask->footer != IRQ_MASK_FOOTER) {
return -1;
}
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x4),
mask->mask1);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x8),
mask->mask2);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0xc),
mask->mask3);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x10),
mask->mask4);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x14),
mask->mask5);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x18),
mask->mask6);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x1c),
mask->mask7);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x20),
mask->mask8);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x24),
mask->mask9);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x28),
mask->mask10);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x2c),
mask->mask11);
mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x30),
mask->mask12);
/* make sure dist changes happen */
dsb();
return 0;
}
/*
* mt_irq_mask_all: disable all interrupts
* @mask: pointer to struct mtk_irq_mask for storing the original mask value.
* Return 0 for success; return negative values for failure.
* (This is ONLY used for the idle current measurement by the factory mode.)
*/
int mt_irq_mask_all(struct mtk_irq_mask *mask)
{
if (mask != NULL) {
/* for SPI */
mask->mask1 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x4));
mask->mask2 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x8));
mask->mask3 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0xc));
mask->mask4 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x10));
mask->mask5 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x14));
mask->mask6 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x18));
mask->mask7 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x1c));
mask->mask8 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x20));
mask->mask9 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x24));
mask->mask10 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x28));
mask->mask11 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x2c));
mask->mask12 = mmio_read_32((BASE_GICD_BASE +
GICD_ISENABLER + 0x30));
/* for SPI */
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x4),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x8),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0xC),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x10),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x14),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x18),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x1C),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x20),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x24),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x28),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x2c),
0xFFFFFFFF);
mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x30),
0xFFFFFFFF);
/* make sure distributor changes happen */
dsb();
mask->header = IRQ_MASK_HEADER;
mask->footer = IRQ_MASK_FOOTER;
return 0;
} else {
return -1;
}
}
static uint32_t mt_irq_get_pol(uint32_t irq)
{
#ifdef CIRQ_WITH_POLARITY
uint32_t reg;
uint32_t base = INT_POL_CTL0;
if (irq < 32U) {
return 0;
}
reg = ((irq - 32U) / 32U);
return mmio_read_32(base + reg * 4U);
#else
return 0;
#endif
}
unsigned int mt_irq_get_sens(unsigned int irq)
{
unsigned int config;
/*
* 2'b10 edge
* 2'b01 level
*/
config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U);
config = (config >> (irq % 16U) * 2U) & 0x3;
return config;
}
static void collect_all_wakeup_events(void)
{
unsigned int i;
uint32_t gic_irq;
uint32_t cirq;
uint32_t cirq_reg;
uint32_t cirq_offset;
uint32_t mask;
uint32_t pol_mask;
uint32_t irq_offset;
uint32_t irq_mask;
if ((cirq_all_events.wakeup_events == NULL) ||
cirq_all_events.num_of_events == 0U) {
return;
}
for (i = 0U; i < cirq_all_events.num_of_events; i++) {
if (cirq_all_events.wakeup_events[i] > 0U) {
gic_irq = cirq_all_events.wakeup_events[i];
cirq = gic_irq - cirq_all_events.spi_start - 32U;
cirq_reg = cirq / 32U;
cirq_offset = cirq % 32U;
mask = 0x1 << cirq_offset;
irq_offset = gic_irq % 32U;
irq_mask = 0x1 << irq_offset;
/*
* CIRQ default masks all
*/
cirq_all_events.table[cirq_reg].mask |= mask;
/*
* CIRQ default pol is low
*/
pol_mask = mt_irq_get_pol(
cirq_all_events.wakeup_events[i])
& irq_mask;
/*
* 0 means rising
*/
if (pol_mask == 0U) {
cirq_all_events.table[cirq_reg].pol |= mask;
}
/*
* CIRQ could monitor edge/level trigger
* cirq register (0: edge, 1: level)
*/
if (mt_irq_get_sens(cirq_all_events.wakeup_events[i])
== SENS_EDGE) {
cirq_all_events.table[cirq_reg].sen |= mask;
}
cirq_all_events.table[cirq_reg].used = 1U;
cirq_all_events.table[cirq_reg].reg_num = cirq_reg;
}
}
}
/*
* mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number.
* @cirq_num: the SYS_CIRQ number to set
* @pol: polarity to set
* @return:
* 0: set pol success
* -1: cirq num is out of range
*/
#ifdef CIRQ_WITH_POLARITY
static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol)
{
uint32_t base;
uint32_t bit = 1U << (cirq_num % 32U);
if (cirq_num >= CIRQ_IRQ_NUM) {
return -1;
}
if (pol == MT_CIRQ_POL_NEG) {
base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE;
} else if (pol == MT_CIRQ_POL_POS) {
base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE;
} else {
return -1;
}
mmio_write_32(base, bit);
return 0;
}
#endif
/*
* mt_cirq_mask: Mask the specified SYS_CIRQ.
* @cirq_num: the SYS_CIRQ number to mask
* @return:
* 0: mask success
* -1: cirq num is out of range
*/
static int mt_cirq_mask(uint32_t cirq_num)
{
uint32_t bit = 1U << (cirq_num % 32U);
if (cirq_num >= CIRQ_IRQ_NUM) {
return -1;
}
mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit);
return 0;
}
/*
* mt_cirq_unmask: Unmask the specified SYS_CIRQ.
* @cirq_num: the SYS_CIRQ number to unmask
* @return:
* 0: umask success
* -1: cirq num is out of range
*/
static int mt_cirq_unmask(uint32_t cirq_num)
{
uint32_t bit = 1U << (cirq_num % 32U);
if (cirq_num >= CIRQ_IRQ_NUM) {
return -1;
}
mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit);
return 0;
}
uint32_t mt_irq_get_en(uint32_t irq)
{
uint32_t addr, st, val;
addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U;
st = mmio_read_32(addr);
val = (st >> (irq % 32U)) & 1U;
return val;
}
static void __cirq_fast_clone(void)
{
struct cirq_reg *reg;
unsigned int i;
for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
uint32_t cirq_bit;
reg = &cirq_all_events.table[i];
if (reg->used == 0U) {
continue;
}
mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U),
reg->sen);
for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
uint32_t val, cirq_id;
uint32_t gic_id;
#ifdef CIRQ_WITH_POLARITY
uint32_t gic_bit, pol;
#endif
uint32_t en;
val = ((1U << cirq_bit) & reg->mask);
if (val == 0U) {
continue;
}
cirq_id = (reg->reg_num << 5U) + cirq_bit;
gic_id = CIRQ_TO_IRQ_NUM(cirq_id);
#ifdef CIRQ_WITH_POLARITY
gic_bit = (0x1U << ((gic_id - 32U) % 32U));
pol = mt_irq_get_pol(gic_id) & gic_bit;
if (pol != 0U) {
mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_NEG);
} else {
mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_POS);
}
#endif
en = mt_irq_get_en(gic_id);
if (en == 1U) {
mt_cirq_unmask(cirq_id);
} else {
mt_cirq_mask(cirq_id);
}
}
}
}
static void cirq_fast_clone(void)
{
if (already_cloned == 0U) {
collect_all_wakeup_events();
already_cloned = 1U;
}
__cirq_fast_clone();
}
void set_wakeup_sources(uint32_t *list, uint32_t num_of_events)
{
cirq_all_events.num_of_events = num_of_events;
cirq_all_events.wakeup_events = list;
}
/*
* mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ
*/
void mt_cirq_clone_gic(void)
{
cirq_fast_clone();
}
uint32_t mt_irq_get_pending_vec(uint32_t start_irq)
{
uint32_t base = 0U;
uint32_t pending_vec = 0U;
uint32_t reg = start_irq / 32U;
uint32_t LSB_num, MSB_num;
uint32_t LSB_vec, MSB_vec;
base = BASE_GICD_BASE;
/* if start_irq is not aligned 32, do some assembling */
MSB_num = start_irq % 32U;
if (MSB_num != 0U) {
LSB_num = 32U - MSB_num;
LSB_vec = mmio_read_32(base + GICD_ISPENDR +
reg * 4U) >> MSB_num;
MSB_vec = mmio_read_32(base + GICD_ISPENDR +
(reg + 1U) * 4U) << LSB_num;
pending_vec = MSB_vec | LSB_vec;
} else {
pending_vec = mmio_read_32(base + GICD_ISPENDR + reg * 4);
}
return pending_vec;
}
static int mt_cirq_get_mask_vec(unsigned int i)
{
return mmio_read_32((i * 4U) + CIRQ_MASK_BASE);
}
/*
* mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ
*/
void mt_cirq_ack_all(void)
{
uint32_t ack_vec, pend_vec, mask_vec;
unsigned int i;
for (i = 0; i < CIRQ_CTRL_REG_NUM; i++) {
/*
* if a irq is pending & not masked, don't ack it
* , since cirq start irq might not be 32 aligned with gic,
* need an exotic API to get proper vector of pending irq
*/
pend_vec = mt_irq_get_pending_vec(CIRQ_SPI_START
+ (i + 1U) * 32U);
mask_vec = mt_cirq_get_mask_vec(i);
/* those should be acked are: "not (pending & not masked)",
*/
ack_vec = (~pend_vec) | mask_vec;
mmio_write_32(CIRQ_ACK_BASE + (i * 4U), ack_vec);
}
/*
* make sure all cirq setting take effect
* before doing other things
*/
dsb();
}
/*
* mt_cirq_enable: Enable SYS_CIRQ
*/
void mt_cirq_enable(void)
{
uint32_t st;
/* level only */
mt_cirq_ack_all();
st = mmio_read_32(CIRQ_CON);
/*
* CIRQ could monitor edge/level trigger
*/
st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS);
mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
}
/*
* mt_cirq_disable: Disable SYS_CIRQ
*/
void mt_cirq_disable(void)
{
uint32_t st;
st = mmio_read_32(CIRQ_CON);
st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS);
mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
}
void mt_irq_unmask_for_sleep_ex(uint32_t irq)
{
uint32_t mask;
mask = 1U << (irq % 32U);
mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER +
((irq / 32U) * 4U), mask);
}
void mt_cirq_mask_all(void)
{
unsigned int i;
for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF);
}
dsb();
}
static void cirq_fast_sw_flush(void)
{
struct cirq_reg *reg;
unsigned int i;
for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
uint32_t cirq_bit;
reg = &cirq_all_events.table[i];
if (reg->used == 0U) {
continue;
}
reg->pending = mmio_read_32(CIRQ_STA_BASE +
(reg->reg_num << 2U));
reg->pending &= reg->mask;
for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
uint32_t val, cirq_id;
val = (1U << cirq_bit) & reg->pending;
if (val == 0U) {
continue;
}
cirq_id = (reg->reg_num << 5U) + cirq_bit;
mt_irq_set_pending(CIRQ_TO_IRQ_NUM(cirq_id));
if (CIRQ_TO_IRQ_NUM(cirq_id) == MD_WDT_IRQ_BIT_ID) {
INFO("Set MD_WDT_IRQ pending in %s\n",
__func__);
}
}
}
}
/*
* mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC
*/
void mt_cirq_flush(void)
{
cirq_fast_sw_flush();
mt_cirq_mask_all();
mt_cirq_ack_all();
}
void mt_cirq_sw_reset(void)
{
uint32_t st;
st = mmio_read_32(CIRQ_CON);
st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS);
mmio_write_32(CIRQ_CON, st);
}
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLAT_MT_CIRQ_H
#define PLAT_MT_CIRQ_H
#include <stdint.h>
#include <platform_def.h>
enum {
IRQ_MASK_HEADER = 0xF1F1F1F1,
IRQ_MASK_FOOTER = 0xF2F2F2F2
};
struct mtk_irq_mask {
uint32_t header; /* for error checking */
uint32_t mask0;
uint32_t mask1;
uint32_t mask2;
uint32_t mask3;
uint32_t mask4;
uint32_t mask5;
uint32_t mask6;
uint32_t mask7;
uint32_t mask8;
uint32_t mask9;
uint32_t mask10;
uint32_t mask11;
uint32_t mask12;
uint32_t footer; /* for error checking */
};
/*
* Define hardware register
*/
#define CIRQ_STA_BASE (SYS_CIRQ_BASE + U(0x000))
#define CIRQ_ACK_BASE (SYS_CIRQ_BASE + U(0x080))
#define CIRQ_MASK_BASE (SYS_CIRQ_BASE + U(0x100))
#define CIRQ_MASK_SET_BASE (SYS_CIRQ_BASE + U(0x180))
#define CIRQ_MASK_CLR_BASE (SYS_CIRQ_BASE + U(0x200))
#define CIRQ_SENS_BASE (SYS_CIRQ_BASE + U(0x280))
#define CIRQ_SENS_SET_BASE (SYS_CIRQ_BASE + U(0x300))
#define CIRQ_SENS_CLR_BASE (SYS_CIRQ_BASE + U(0x380))
#define CIRQ_POL_BASE (SYS_CIRQ_BASE + U(0x400))
#define CIRQ_POL_SET_BASE (SYS_CIRQ_BASE + U(0x480))
#define CIRQ_POL_CLR_BASE (SYS_CIRQ_BASE + U(0x500))
#define CIRQ_CON (SYS_CIRQ_BASE + U(0x600))
/*
* Register placement
*/
#define CIRQ_CON_EN_BITS U(0)
#define CIRQ_CON_EDGE_ONLY_BITS U(1)
#define CIRQ_CON_FLUSH_BITS U(2)
#define CIRQ_CON_SW_RST_BITS U(20)
#define CIRQ_CON_EVENT_BITS U(31)
#define CIRQ_CON_BITS_MASK U(0x7)
/*
* Register setting
*/
#define CIRQ_CON_EN U(0x1)
#define CIRQ_CON_EDGE_ONLY U(0x1)
#define CIRQ_CON_FLUSH U(0x1)
#define CIRQ_SW_RESET U(0x1)
/*
* Define constant
*/
#define CIRQ_CTRL_REG_NUM ((CIRQ_IRQ_NUM + 31U) / 32U)
#define MT_CIRQ_POL_NEG U(0)
#define MT_CIRQ_POL_POS U(1)
#define IRQ_TO_CIRQ_NUM(irq) ((irq) - (32U + CIRQ_SPI_START))
#define CIRQ_TO_IRQ_NUM(cirq) ((cirq) + (32U + CIRQ_SPI_START))
/* GIC sensitive */
#define SENS_EDGE U(0x2)
#define SENS_LEVEL U(0x1)
/*
* Define function prototypes.
*/
int mt_cirq_test(void);
void mt_cirq_dump_reg(void);
int mt_irq_mask_restore(struct mtk_irq_mask *mask);
int mt_irq_mask_all(struct mtk_irq_mask *mask);
void mt_cirq_clone_gic(void);
void mt_cirq_enable(void);
void mt_cirq_flush(void);
void mt_cirq_disable(void);
void mt_irq_unmask_for_sleep_ex(uint32_t irq);
void set_wakeup_sources(uint32_t *list, uint32_t num_of_events);
void mt_cirq_sw_reset(void);
struct cirq_reg {
uint32_t reg_num;
uint32_t used;
uint32_t mask;
uint32_t pol;
uint32_t sen;
uint32_t pending;
uint32_t the_link;
};
struct cirq_events {
uint32_t num_reg;
uint32_t spi_start;
uint32_t num_of_events;
uint32_t *wakeup_events;
struct cirq_reg table[CIRQ_REG_NUM];
uint32_t dist_base;
uint32_t cirq_base;
uint32_t used_reg_head;
};
#endif /* PLAT_MT_CIRQ_H */
@@ -0,0 +1,14 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := cirq
LOCAL_SRCS-y := $(LOCAL_DIR)/mt_cirq.c
PLAT_INCLUDES += -I${LOCAL_DIR}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,466 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <lib/spinlock.h>
#include <lib/mtk_init/mtk_init.h>
#include <lib/pm/mtk_pm.h>
#include "mt_cpu_pm.h"
#include "mt_cpu_pm_cpc.h"
#include "mt_cpu_pm_mbox.h"
#include <mt_lp_rm.h>
#include "mt_smp.h"
#include <mtk_mmap_pool.h>
#include <platform_def.h>
/*
* The locker must use the bakery locker when cache turns off.
* Using spin_lock will gain better performance.
*/
#ifdef MT_CPU_PM_USING_BAKERY_LOCK
DEFINE_BAKERY_LOCK(mt_cpu_pm_lock);
#define plat_cpu_pm_lock_init() bakery_lock_init(&mt_cpu_pm_lock)
#define plat_cpu_pm_lock() bakery_lock_get(&mt_cpu_pm_lock)
#define plat_cpu_pm_unlock() bakery_lock_release(&mt_cpu_pm_lock)
#else
spinlock_t mt_cpu_pm_lock;
#define plat_cpu_pm_lock_init()
#define plat_cpu_pm_lock() spin_lock(&mt_cpu_pm_lock)
#define plat_cpu_pm_unlock() spin_unlock(&mt_cpu_pm_lock)
#endif
enum mt_pwr_node {
MT_PWR_NONMCUSYS = 0,
MT_PWR_MCUSYS_PDN,
MT_PWR_SUSPEND,
MT_PWR_SYSTEM_MEM,
MT_PWR_SYSTEM_PLL,
MT_PWR_SYSTEM_BUS,
MT_PWR_MAX,
};
#define CPU_PM_DEPD_INIT BIT(0)
#define CPU_PM_DEPD_READY BIT(1)
#define CPU_PM_PLAT_READY BIT(2)
#ifdef CPU_PM_TINYSYS_SUPPORT
#define CPU_PM_INIT_READY (CPU_PM_DEPD_INIT | CPU_PM_DEPD_READY)
#define CPU_PM_LP_READY (CPU_PM_INIT_READY | CPU_PM_PLAT_READY)
#else
#define CPU_PM_LP_READY (CPU_PM_PLAT_READY)
#endif
#if CONFIG_MTK_PM_SUPPORT
#if CONFIG_MTK_CPU_SUSPEND_EN || CONFIG_MTK_SMP_EN
static void cpupm_cpu_resume_common(const struct mtk_cpupm_pwrstate *state)
{
CPU_PM_ASSERT(state != NULL);
mtk_cpc_core_on_hint_clr(state->info.cpuid);
}
#endif
#if CONFIG_MTK_SMP_EN
static int cpupm_cpu_pwr_on_prepare(unsigned int cpu, uintptr_t entry)
{
struct cpu_pwr_ctrl pwr_ctrl;
PER_CPU_PWR_CTRL(pwr_ctrl, cpu);
mt_smp_core_bootup_address_set(&pwr_ctrl, entry);
mt_smp_core_init_arch(0, cpu, 1, &pwr_ctrl);
return mt_smp_power_core_on(cpu, &pwr_ctrl);
}
static void cpupm_cpu_resume_smp(const struct mtk_cpupm_pwrstate *state)
{
CPU_PM_ASSERT(state != NULL);
plat_cpu_pm_lock();
mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
GIC_WAKEUP_IGNORE(state->info.cpuid));
plat_cpu_pm_unlock();
cpupm_cpu_resume_common(state);
}
static void cpupm_cpu_suspend_smp(const struct mtk_cpupm_pwrstate *state)
{
struct cpu_pwr_ctrl pwr_ctrl;
CPU_PM_ASSERT(state != NULL);
PER_CPU_PWR_CTRL(pwr_ctrl, state->info.cpuid);
mt_smp_power_core_off(&pwr_ctrl);
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
GIC_WAKEUP_IGNORE(state->info.cpuid));
}
static void cpupm_smp_init(unsigned int cpu, uintptr_t sec_entrypoint)
{
unsigned int reg;
struct mtk_cpupm_pwrstate state = {
.info = {
.cpuid = cpu,
.mode = MTK_CPU_PM_SMP,
},
.pwr = {
.afflv = 0,
.state_id = 0,
},
};
reg = mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG);
if ((reg & CPC_MCUSYS_CPC_RESET_PWR_ON_EN) != 0) {
INFO("[%s:%d][CPU_PM] reset pwr on is enabled then clear it!\n",
__func__, __LINE__);
mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_MCUSYS_CPC_RESET_PWR_ON_EN);
}
cpupm_cpu_pwr_on_prepare(cpu, sec_entrypoint);
cpupm_cpu_resume_smp(&state);
}
static struct mtk_cpu_smp_ops cpcv3_2_cpu_smp = {
.init = cpupm_smp_init,
.cpu_pwr_on_prepare = cpupm_cpu_pwr_on_prepare,
.cpu_on = cpupm_cpu_resume_smp,
.cpu_off = cpupm_cpu_suspend_smp,
};
#endif /* CONFIG_MTK_SMP_EN */
#if CONFIG_MTK_CPU_SUSPEND_EN
#define CPUPM_READY_MS (40000)
#define CPUPM_ARCH_TIME_MS(ms) (ms * 1000 * SYS_COUNTER_FREQ_IN_MHZ)
#define CPUPM_BOOTUP_TIME_THR CPUPM_ARCH_TIME_MS(CPUPM_READY_MS)
static int mt_pwr_nodes[MT_PWR_MAX];
static int plat_mt_lp_cpu_rc;
static unsigned int cpu_pm_status;
static unsigned int plat_prev_stateid;
static int mcusys_prepare_suspend(const struct mtk_cpupm_pwrstate *state)
{
unsigned int stateid = state->pwr.state_id;
if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
goto mt_pwr_mcusysoff_break;
}
if (!IS_PLAT_SUSPEND_ID(stateid)) {
if (mt_pwr_nodes[MT_PWR_SYSTEM_MEM] != 0) {
stateid = MT_PLAT_PWR_STATE_SYSTEM_MEM;
} else if (mt_pwr_nodes[MT_PWR_SYSTEM_PLL] != 0) {
stateid = MT_PLAT_PWR_STATE_SYSTEM_PLL;
} else if (mt_pwr_nodes[MT_PWR_SYSTEM_BUS] != 0) {
stateid = MT_PLAT_PWR_STATE_SYSTEM_BUS;
} else if (mt_pwr_nodes[MT_PWR_SUSPEND] != 0) {
stateid = MT_PLAT_PWR_STATE_SUSPEND;
} else {
stateid = MT_PLAT_PWR_STATE_MCUSYS;
}
}
plat_prev_stateid = stateid;
plat_mt_lp_cpu_rc = mt_lp_rm_find_and_run_constraint(0, state->info.cpuid, stateid, NULL);
if (plat_mt_lp_cpu_rc < 0) {
goto mt_pwr_mcusysoff_reflect;
}
#ifdef CPU_PM_TINYSYS_SUPPORT
mtk_set_cpu_pm_preffered_cpu(state->info.cpuid);
#endif
return MTK_CPUPM_E_OK;
mt_pwr_mcusysoff_reflect:
mtk_cpc_mcusys_off_reflect();
mt_pwr_mcusysoff_break:
plat_mt_lp_cpu_rc = -1;
return MTK_CPUPM_E_FAIL;
}
static int mcusys_prepare_resume(const struct mtk_cpupm_pwrstate *state)
{
if (plat_mt_lp_cpu_rc < 0) {
return MTK_CPUPM_E_FAIL;
}
mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, state->info.cpuid, plat_prev_stateid);
mtk_cpc_mcusys_off_reflect();
return MTK_CPUPM_E_OK;
}
static unsigned int cpupm_do_pstate_off(const mtk_pstate_type psci_state,
const struct mtk_cpupm_pwrstate *state)
{
unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE;
if (!state || (state->pwr.afflv > PLAT_MAX_PWR_LVL)) {
CPU_PM_ASSERT(0);
}
switch (state->pwr.state_id) {
case MT_PLAT_PWR_STATE_SYSTEM_MEM:
mt_pwr_nodes[MT_PWR_SYSTEM_MEM] += 1;
break;
case MT_PLAT_PWR_STATE_SYSTEM_PLL:
mt_pwr_nodes[MT_PWR_SYSTEM_PLL] += 1;
break;
case MT_PLAT_PWR_STATE_SYSTEM_BUS:
mt_pwr_nodes[MT_PWR_SYSTEM_BUS] += 1;
break;
case MT_PLAT_PWR_STATE_SUSPEND:
mt_pwr_nodes[MT_PWR_SUSPEND] += 1;
break;
default:
if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id) &&
!IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv)) {
plat_cpu_pm_lock();
mt_pwr_nodes[MT_PWR_NONMCUSYS] += 1;
flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_NONMCUSYS],
sizeof(mt_pwr_nodes[MT_PWR_NONMCUSYS]));
plat_cpu_pm_unlock();
}
break;
}
if ((mt_pwr_nodes[MT_PWR_NONMCUSYS] == 0) && IS_PLAT_MCUSYSOFF_AFFLV(state->pwr.afflv)) {
/* Prepare to power down mcusys */
if (mcusys_prepare_suspend(state) == MTK_CPUPM_E_OK) {
mt_pwr_nodes[MT_PWR_MCUSYS_PDN] += 1;
flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_MCUSYS_PDN],
sizeof(mt_pwr_nodes[MT_PWR_MCUSYS_PDN]));
pstate |= (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER);
}
}
if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
}
if (psci_get_pstate_pwrlvl(psci_state) >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
}
return pstate;
}
static unsigned int cpupm_do_pstate_on(const mtk_pstate_type psci_state,
const struct mtk_cpupm_pwrstate *state)
{
unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE;
CPU_PM_ASSERT(state != NULL);
if (state->pwr.afflv > PLAT_MAX_PWR_LVL) {
CPU_PM_ASSERT(0);
}
if (mt_pwr_nodes[MT_PWR_MCUSYS_PDN] != 0) {
mt_pwr_nodes[MT_PWR_MCUSYS_PDN] = 0;
flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_MCUSYS_PDN],
sizeof(mt_pwr_nodes[MT_PWR_MCUSYS_PDN]));
pstate |= (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER);
mcusys_prepare_resume(state);
}
if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
}
switch (state->pwr.state_id) {
case MT_PLAT_PWR_STATE_SYSTEM_MEM:
mt_pwr_nodes[MT_PWR_SYSTEM_MEM] -= 1;
CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_MEM] >= 0);
break;
case MT_PLAT_PWR_STATE_SYSTEM_PLL:
mt_pwr_nodes[MT_PWR_SYSTEM_PLL] -= 1;
CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_PLL] >= 0);
break;
case MT_PLAT_PWR_STATE_SYSTEM_BUS:
mt_pwr_nodes[MT_PWR_SYSTEM_BUS] -= 1;
CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_BUS] >= 0);
break;
case MT_PLAT_PWR_STATE_SUSPEND:
mt_pwr_nodes[MT_PWR_SUSPEND] -= 1;
CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SUSPEND] >= 0);
break;
default:
if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id) &&
!IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv)) {
plat_cpu_pm_lock();
mt_pwr_nodes[MT_PWR_NONMCUSYS] -= 1;
flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_NONMCUSYS],
sizeof(mt_pwr_nodes[MT_PWR_NONMCUSYS]));
plat_cpu_pm_unlock();
}
break;
}
if (IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv) ||
(IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv) && (mt_pwr_nodes[MT_PWR_SUSPEND] > 0))) {
mtk_cpc_time_sync();
}
if (mt_pwr_nodes[MT_PWR_NONMCUSYS] < 0) {
CPU_PM_ASSERT(0);
}
pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
return pstate;
}
static void cpupm_cpu_resume(const struct mtk_cpupm_pwrstate *state)
{
cpupm_cpu_resume_common(state);
}
static void cpupm_mcusys_resume(const struct mtk_cpupm_pwrstate *state)
{
assert(state != NULL);
}
static void cpupm_mcusys_suspend(const struct mtk_cpupm_pwrstate *state)
{
assert(state != NULL);
}
static unsigned int cpupm_get_pstate(enum mt_cpupm_pwr_domain domain,
const mtk_pstate_type psci_state,
const struct mtk_cpupm_pwrstate *state)
{
unsigned int pstate = 0;
if (state == NULL) {
return 0;
}
if (state->info.mode == MTK_CPU_PM_SMP) {
pstate = MT_CPUPM_PWR_DOMAIN_CORE;
} else {
if (domain == CPUPM_PWR_OFF) {
pstate = cpupm_do_pstate_off(psci_state, state);
} else if (domain == CPUPM_PWR_ON) {
pstate = cpupm_do_pstate_on(psci_state, state);
} else {
INFO("[%s:%d][CPU_PM] unknown pwr domain :%d\n",
__func__, __LINE__, domain);
assert(0);
}
}
return pstate;
}
static int cpupm_init(void)
{
int ret = MTK_CPUPM_E_OK;
#ifdef CPU_PM_TINYSYS_SUPPORT
int status;
if ((cpu_pm_status & CPU_PM_INIT_READY) == CPU_PM_INIT_READY) {
return MTK_CPUPM_E_OK;
}
if (!(cpu_pm_status & CPU_PM_DEPD_INIT)) {
status = mtk_lp_depd_condition(CPUPM_MBOX_WAIT_DEV_INIT);
if (status == 0) {
plat_cpu_pm_lock();
cpu_pm_status |= CPU_PM_DEPD_INIT;
plat_cpu_pm_unlock();
}
}
if ((cpu_pm_status & CPU_PM_DEPD_INIT) && !(cpu_pm_status & CPU_PM_DEPD_READY)) {
status = mtk_lp_depd_condition(CPUPM_MBOX_WAIT_TASK_READY);
if (status == 0) {
plat_cpu_pm_lock();
cpu_pm_status |= CPU_PM_DEPD_READY;
plat_cpu_pm_unlock();
}
}
ret = ((cpu_pm_status & CPU_PM_INIT_READY) == CPU_PM_INIT_READY) ?
MTK_CPUPM_E_OK : MTK_CPUPM_E_FAIL;
#endif
return ret;
}
static int cpupm_pwr_state_valid(unsigned int afflv, unsigned int state)
{
if (cpu_pm_status == CPU_PM_LP_READY) {
return MTK_CPUPM_E_OK;
}
if (cpupm_init() != MTK_CPUPM_E_OK) {
return MTK_CPUPM_E_FAIL;
}
if (read_cntpct_el0() >= (uint64_t)CPUPM_BOOTUP_TIME_THR) {
plat_cpu_pm_lock();
cpu_pm_status |= CPU_PM_PLAT_READY;
plat_cpu_pm_unlock();
}
if (!IS_PLAT_SYSTEM_SUSPEND(afflv) && (cpu_pm_status & CPU_PM_PLAT_READY) == 0) {
return MTK_CPUPM_E_FAIL;
}
return MTK_CPUPM_E_OK;
}
static struct mtk_cpu_pm_ops cpcv3_2_mcdi = {
.get_pstate = cpupm_get_pstate,
.pwr_state_valid = cpupm_pwr_state_valid,
.cpu_resume = cpupm_cpu_resume,
.mcusys_suspend = cpupm_mcusys_suspend,
.mcusys_resume = cpupm_mcusys_resume,
};
#endif /* CONFIG_MTK_CPU_SUSPEND_EN */
#endif /* CONFIG_MTK_PM_SUPPORT */
/*
* Depend on mtk pm methodology, the psci op init must
* be invoked after cpu pm to avoid initialization fail.
*/
int mt_plat_cpu_pm_init(void)
{
plat_cpu_pm_lock_init();
mtk_cpc_init();
#if CONFIG_MTK_PM_SUPPORT
#if CONFIG_MTK_CPU_SUSPEND_EN
register_cpu_pm_ops(CPU_PM_FN, &cpcv3_2_mcdi);
#endif /* CONFIG_MTK_CPU_SUSPEND_EN */
#if CONFIG_MTK_SMP_EN
register_cpu_smp_ops(CPU_PM_FN, &cpcv3_2_cpu_smp);
#endif /* CONFIG_MTK_SMP_EN */
#endif /* CONFIG_MTK_PM_SUPPORT */
INFO("[%s:%d] - CPU PM INIT finished\n", __func__, __LINE__);
return 0;
}
MTK_ARCH_INIT(mt_plat_cpu_pm_init);
static const mmap_region_t cpu_pm_mmap[] MTK_MMAP_SECTION = {
#ifdef CPU_PM_TINYSYS_SUPPORT
#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN
MAP_REGION_FLAT(CPU_EB_TCM_BASE, CPU_EB_TCM_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
#endif
#endif
{0}
};
DECLARE_MTK_MMAP_REGIONS(cpu_pm_mmap);
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_H
#define MT_CPU_PM_H
#include <assert.h>
#include <mcucfg.h>
#include <platform_def.h>
/*
* After ARM v8.2, the cache will turn off automatically when powering down CPU. Therefore, there
* is no doubt to use the spin_lock here.
*/
#if !HW_ASSISTED_COHERENCY
#define MT_CPU_PM_USING_BAKERY_LOCK
#endif
#define CPU_PM_FN (MTK_CPUPM_FN_CPUPM_GET_PWR_STATE | \
MTK_CPUPM_FN_PWR_STATE_VALID | \
MTK_CPUPM_FN_PWR_ON_CORE_PREPARE | \
MTK_CPUPM_FN_RESUME_CORE | \
MTK_CPUPM_FN_SUSPEND_MCUSYS | \
MTK_CPUPM_FN_RESUME_MCUSYS | \
MTK_CPUPM_FN_SMP_INIT | \
MTK_CPUPM_FN_SMP_CORE_ON | \
MTK_CPUPM_FN_SMP_CORE_OFF)
#define CPU_PM_ASSERT(_cond) ({ \
if (!(_cond)) { \
INFO("[%s:%d] - %s\n", __func__, __LINE__, #_cond); \
panic(); \
} })
#define CPC_PWR_MASK_MCUSYS_MP0 (0xC001)
#define PER_CPU_PWR_DATA(ctrl, cluster, core) \
do { \
ctrl.rvbaraddr_l = CORE_RVBRADDR_##cluster##_##core##_L; \
ctrl.arch_addr = MCUCFG_MP0_CLUSTER_CFG5; \
ctrl.pwpr = SPM_MP##cluster##_CPU##core##_PWR_CON; \
} while (0)
#define PER_CPU_PWR_CTRL(ctrl, cpu) ({ \
switch (cpu) { \
case 0: \
PER_CPU_PWR_DATA(ctrl, 0, 0); \
break; \
case 1: \
PER_CPU_PWR_DATA(ctrl, 0, 1); \
break; \
case 2: \
PER_CPU_PWR_DATA(ctrl, 0, 2); \
break; \
case 3: \
PER_CPU_PWR_DATA(ctrl, 0, 3); \
break; \
case 4: \
PER_CPU_PWR_DATA(ctrl, 0, 4); \
break; \
case 5: \
PER_CPU_PWR_DATA(ctrl, 0, 5); \
break; \
case 6: \
PER_CPU_PWR_DATA(ctrl, 0, 6); \
break; \
case 7: \
PER_CPU_PWR_DATA(ctrl, 0, 7); \
break; \
default: \
assert(0); \
break; \
} })
/* MCUSYS DREQ BIG VPROC ISO control */
#define DREQ20_BIG_VPROC_ISO (MCUCFG_BASE + 0xad8c)
/* Definition about bootup address for each core CORE_RVBRADDR_clusterid_cpuid */
#define CORE_RVBRADDR_0_0_L (MCUCFG_BASE + 0xc900)
#define CORE_RVBRADDR_0_1_L (MCUCFG_BASE + 0xc908)
#define CORE_RVBRADDR_0_2_L (MCUCFG_BASE + 0xc910)
#define CORE_RVBRADDR_0_3_L (MCUCFG_BASE + 0xc918)
#define CORE_RVBRADDR_0_4_L (MCUCFG_BASE + 0xc920)
#define CORE_RVBRADDR_0_5_L (MCUCFG_BASE + 0xc928)
#define CORE_RVBRADDR_0_6_L (MCUCFG_BASE + 0xc930)
#define CORE_RVBRADDR_0_7_L (MCUCFG_BASE + 0xc938)
#define MCUCFG_MP0_CLUSTER_CFG5 (MCUCFG_BASE + 0xc8e4)
struct cpu_pwr_ctrl {
unsigned int rvbaraddr_l;
unsigned int arch_addr;
unsigned int pwpr;
};
#define MCUSYS_STATUS_PDN BIT(0)
#define MCUSYS_STATUS_CPUSYS_PROTECT BIT(8)
#define MCUSYS_STATUS_MCUSYS_PROTECT BIT(9)
/* cpu_pm function ID */
enum mt_cpu_pm_user_id {
MCUSYS_STATUS,
CPC_COMMAND,
};
/* cpu_pm lp function ID */
enum mt_cpu_pm_lp_smc_id {
LP_CPC_COMMAND,
IRQS_REMAIN_ALLOC,
IRQS_REMAIN_CTRL,
IRQS_REMAIN_IRQ,
IRQS_REMAIN_WAKEUP_CAT,
IRQS_REMAIN_WAKEUP_SRC,
};
#endif /* MT_CPU_PM_H */
@@ -0,0 +1,253 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <drivers/delay_timer.h>
#include "mt_cpu_pm.h"
#include "mt_cpu_pm_cpc.h"
#include "mt_smp.h"
#include <mt_timer.h>
struct mtk_cpc_dev {
int auto_off;
unsigned int auto_thres_tick;
};
static struct mtk_cpc_dev cpc;
static int mtk_cpc_last_core_prot(int prot_req, int resp_reg, int resp_ofs)
{
unsigned int staus;
unsigned int retry = 0;
while (retry < RETRY_CNT_MAX) {
retry++;
mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
udelay(1);
staus = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
if (staus == PROT_SUCCESS) {
return CPC_SUCCESS;
} else if (staus == PROT_GIVEUP) {
return CPC_ERR_FAIL;
}
}
return CPC_ERR_TIMEOUT;
}
static int mtk_cpu_pm_mcusys_prot_aquire(void)
{
return mtk_cpc_last_core_prot(MCUSYS_PROT_SET, CPC_MCUSYS_LAST_CORE_RESP, MCUSYS_RESP_OFS);
}
static void mtk_cpu_pm_mcusys_prot_release(void)
{
mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
}
int mtk_cpu_pm_cluster_prot_aquire(void)
{
return mtk_cpc_last_core_prot(CPUSYS_PROT_SET, CPC_MCUSYS_MP_LAST_CORE_RESP,
CPUSYS_RESP_OFS);
}
void mtk_cpu_pm_cluster_prot_release(void)
{
mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
}
static void mtk_cpc_cluster_cnt_backup(void)
{
/* single cluster */
uint32_t backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
uint32_t curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
if ((curr_cnt & 0x7fff) == 0) {
curr_cnt = (curr_cnt >> 16) & 0x7fff;
} else {
curr_cnt = curr_cnt & 0x7fff;
}
mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
}
static inline void mtk_cpc_mcusys_off_enable(bool enable)
{
mmio_write_32(CPC_MCUSYS_PWR_CTRL, enable ? 1 : 0);
}
void mtk_cpc_mcusys_off_reflect(void)
{
mtk_cpc_mcusys_off_enable(false);
mtk_cpu_pm_mcusys_prot_release();
}
int mtk_cpc_mcusys_off_prepare(void)
{
if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
return CPC_ERR_FAIL;
}
mtk_cpc_cluster_cnt_backup();
mtk_cpc_mcusys_off_enable(true);
return CPC_SUCCESS;
}
void mtk_cpc_core_on_hint_set(int cpu)
{
mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
}
void mtk_cpc_core_on_hint_clr(int cpu)
{
mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
}
static void mtk_cpc_dump_timestamp(void)
{
unsigned int id;
for (id = 0; id < CPC_TRACE_ID_NUM; id++) {
mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
(const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
CPC_TRACE_SIZE);
}
}
void mtk_cpc_time_sync(void)
{
uint64_t kt;
uint32_t systime_l, systime_h;
kt = sched_clock();
systime_l = mmio_read_32(CNTSYS_L_REG);
systime_h = mmio_read_32(CNTSYS_H_REG);
/* sync kernel timer to cpc */
mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
/* sync system timer to cpc */
mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
}
static void mtk_cpc_config(unsigned int cfg, unsigned int data)
{
switch (cfg) {
case CPC_SMC_CONFIG_PROF:
if (data) {
mmio_setbits_32(CPC_MCUSYS_CPC_DBG_SETTING, CPC_PROF_EN);
} else {
mmio_clrbits_32(CPC_MCUSYS_CPC_DBG_SETTING, CPC_PROF_EN);
}
break;
case CPC_SMC_CONFIG_AUTO_OFF:
if (data) {
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_AUTO_OFF_EN);
cpc.auto_off = 1;
} else {
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_AUTO_OFF_EN);
cpc.auto_off = 0;
}
break;
case CPC_SMC_CONFIG_AUTO_OFF_THRES:
cpc.auto_thres_tick = US_TO_TICKS(data);
mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
break;
case CPC_SMC_CONFIG_CNT_CLR:
mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
break;
case CPC_SMC_CONFIG_TIME_SYNC:
mtk_cpc_time_sync();
break;
default:
break;
}
}
static unsigned int mtk_cpc_read_config(unsigned int cfg)
{
unsigned int res = 0;
switch (cfg) {
case CPC_SMC_CONFIG_PROF:
res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ? 1 : 0;
break;
case CPC_SMC_CONFIG_AUTO_OFF:
res = cpc.auto_off;
break;
case CPC_SMC_CONFIG_AUTO_OFF_THRES:
res = TICKS_TO_US(cpc.auto_thres_tick);
break;
case CPC_SMC_CONFIG_CNT_CLR:
default:
break;
}
return res;
}
uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
{
uint64_t res = 0;
switch (act) {
case CPC_SMC_EVENT_CPC_CONFIG:
mtk_cpc_config((unsigned int)arg1, (unsigned int)arg2);
break;
case CPC_SMC_EVENT_READ_CONFIG:
res = mtk_cpc_read_config((unsigned int)arg1);
break;
case CPC_SMC_EVENT_GIC_DPG_SET:
/* isolated_status = x2; */
default:
break;
}
return res;
}
uint64_t mtk_cpc_trace_dump(uint64_t act, uint64_t arg1, uint64_t arg2)
{
switch (act) {
case CPC_SMC_EVENT_DUMP_TRACE_DATA:
mtk_cpc_dump_timestamp();
break;
default:
break;
}
return 0;
}
void mtk_cpc_init(void)
{
#if CONFIG_MTK_SMP_EN
mt_smp_init();
#endif
mmio_setbits_32(CPC_MCUSYS_CPC_DBG_SETTING, (CPC_DBG_EN | CPC_CALC_EN));
cpc.auto_off = 1;
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, (CPC_OFF_PRE_EN |
((cpc.auto_off > 0) ? CPC_AUTO_OFF_EN : 0)));
mtk_cpc_config(CPC_SMC_CONFIG_AUTO_OFF_THRES, 8000);
/* enable CPC */
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, SSPM_CORE_PWR_ON_EN);
}
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_CPC_H
#define MT_CPU_PM_CPC_H
#include <lib/mmio.h>
#include <mcucfg.h>
#include <platform_def.h>
#define NEED_CPUSYS_PROT_WORKAROUND (1)
/* system sram registers */
#define CPUIDLE_SRAM_REG(r) (CPU_IDLE_SRAM_BASE + (r))
/* db dump */
#define CPC_TRACE_SIZE (0x20)
#define CPC_TRACE_ID_NUM (10)
#define CPC_TRACE_SRAM(id) (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
/* buckup off count */
#define CPC_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1f0)
#define CPC_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1f4)
/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG (0xA814): debug setting */
#define CPC_PWR_ON_SEQ_DIS BIT(1)
#define CPC_PWR_ON_PRIORITY BIT(2)
#define CPC_AUTO_OFF_EN BIT(5)
#define CPC_DORMANT_WAIT_EN BIT(14)
#define CPC_CTRL_EN BIT(16)
#define CPC_OFF_PRE_EN BIT(29)
/* CPC_MCUSYS_LAST_CORE_REQ (0xA818) : last core protection */
#define CPUSYS_PROT_SET BIT(0)
#define MCUSYS_PROT_SET BIT(8)
#define CPUSYS_PROT_CLR BIT(8)
#define MCUSYS_PROT_CLR BIT(9)
#define CPC_PROT_RESP_MASK (0x3)
#define CPUSYS_RESP_OFS (16)
#define MCUSYS_RESP_OFS (30)
#define RETRY_CNT_MAX (1000)
#define PROT_RETRY (0)
#define PROT_SUCCESS (1)
#define PROT_GIVEUP (2)
/* CPC_MCUSYS_CPC_DBG_SETTING (0xAB00): debug setting */
#define CPC_PROF_EN BIT(0)
#define CPC_DBG_EN BIT(1)
#define CPC_FREEZE BIT(2)
#define CPC_CALC_EN BIT(3)
enum mcusys_cpc_lastcore_prot_status {
CPC_SUCCESS = 0,
CPC_ERR_FAIL,
CPC_ERR_TIMEOUT,
NF_CPC_ERR,
};
enum mcusys_cpc_smc_events {
CPC_SMC_EVENT_DUMP_TRACE_DATA,
CPC_SMC_EVENT_GIC_DPG_SET,
CPC_SMC_EVENT_CPC_CONFIG,
CPC_SMC_EVENT_READ_CONFIG,
NF_CPC_SMC_EVENT,
};
enum mcusys_cpc_smc_config {
CPC_SMC_CONFIG_PROF,
CPC_SMC_CONFIG_AUTO_OFF,
CPC_SMC_CONFIG_AUTO_OFF_THRES,
CPC_SMC_CONFIG_CNT_CLR,
CPC_SMC_CONFIG_TIME_SYNC,
NF_CPC_SMC_CONFIG,
};
#define US_TO_TICKS(us) ((us) * 13)
#define TICKS_TO_US(tick) ((tick) / 13)
int mtk_cpu_pm_cluster_prot_aquire(void);
void mtk_cpu_pm_cluster_prot_release(void);
void mtk_cpc_mcusys_off_reflect(void);
int mtk_cpc_mcusys_off_prepare(void);
void mtk_cpc_core_on_hint_set(int cpu);
void mtk_cpc_core_on_hint_clr(int cpu);
void mtk_cpc_time_sync(void);
uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
uint64_t mtk_cpc_trace_dump(uint64_t act, uint64_t arg1, uint64_t arg2);
void mtk_cpc_init(void);
#endif /* MT_CPU_PM_CPC_H */
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <lib/mmio.h>
#include "mt_cpu_pm_mbox.h"
#include <platform_def.h>
#ifdef __GNUC__
#define MCDI_LIKELY(x) __builtin_expect(!!(x), 1)
#define MCDI_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define MCDI_LIKELY(x) (x)
#define MCDI_UNLIKELY(x) (x)
#endif
#define MCUPM_MBOX_3_BASE (CPU_EB_TCM_BASE + CPU_EB_MBOX3_OFFSET)
#define MCUPM_MBOX_WRITE(id, val) mmio_write_32(MCUPM_MBOX_3_BASE + 4 * (id), val)
#define MCUPM_MBOX_READ(id) mmio_read_32(MCUPM_MBOX_3_BASE + 4 * (id))
void mtk_set_mcupm_pll_mode(unsigned int mode)
{
if (mode < NF_MCUPM_ARMPLL_MODE) {
MCUPM_MBOX_WRITE(MCUPM_MBOX_ARMPLL_MODE, mode);
}
}
int mtk_get_mcupm_pll_mode(void)
{
return MCUPM_MBOX_READ(MCUPM_MBOX_ARMPLL_MODE);
}
void mtk_set_mcupm_buck_mode(unsigned int mode)
{
if (mode < NF_MCUPM_BUCK_MODE) {
MCUPM_MBOX_WRITE(MCUPM_MBOX_BUCK_MODE, mode);
}
}
int mtk_get_mcupm_buck_mode(void)
{
return MCUPM_MBOX_READ(MCUPM_MBOX_BUCK_MODE);
}
void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid)
{
return MCUPM_MBOX_WRITE(MCUPM_MBOX_WAKEUP_CPU, cpuid);
}
unsigned int mtk_get_cpu_pm_preffered_cpu(void)
{
return MCUPM_MBOX_READ(MCUPM_MBOX_WAKEUP_CPU);
}
static int mtk_wait_mbox_init_done(void)
{
int status = MCUPM_MBOX_READ(MCUPM_MBOX_TASK_STA);
if (status != MCUPM_TASK_INIT) {
return status;
}
mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
MCUPM_MBOX_WRITE(MCUPM_MBOX_PWR_CTRL_EN, (MCUPM_MCUSYS_CTRL | MCUPM_CM_CTRL |
MCUPM_BUCK_CTRL | MCUPM_ARMPLL_CTRL));
return status;
}
int mtk_lp_depd_condition(enum cpupm_mbox_depd_type type)
{
int status;
if (type == CPUPM_MBOX_WAIT_DEV_INIT) {
status = mtk_wait_mbox_init_done();
if (MCDI_UNLIKELY(status != MCUPM_TASK_INIT)) {
return -ENXIO;
}
MCUPM_MBOX_WRITE(MCUPM_MBOX_AP_READY, 1);
} else if (type == CPUPM_MBOX_WAIT_TASK_READY) {
status = MCUPM_MBOX_READ(MCUPM_MBOX_TASK_STA);
if (MCDI_UNLIKELY((status != MCUPM_TASK_WAIT) &&
(status != MCUPM_TASK_INIT_FINISH))) {
return -ENXIO;
}
}
return 0;
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_CPU_PM_MBOX_H
#define MT_CPU_PM_MBOX_H
#include <lib/utils_def.h>
/* MCUPM Mbox */
/* AP Write */
#define MCUPM_MBOX_AP_READY (0)
#define MCUPM_MBOX_RESERVED_1 (1)
#define MCUPM_MBOX_RESERVED_2 (2)
#define MCUPM_MBOX_RESERVED_3 (3)
#define MCUPM_MBOX_PWR_CTRL_EN (4)
#define MCUPM_MBOX_L3_CACHE_MODE (5)
#define MCUPM_MBOX_BUCK_MODE (6)
#define MCUPM_MBOX_ARMPLL_MODE (7)
/* AP Read */
#define MCUPM_MBOX_TASK_STA (8)
#define MCUPM_MBOX_RESERVED_9 (9)
#define MCUPM_MBOX_RESERVED_10 (10)
#define MCUPM_MBOX_RESERVED_11 (11)
#define MCUPM_MBOX_WAKEUP_CPU (12)
/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN (4) */
#define MCUPM_MCUSYS_CTRL BIT(0)
#define MCUPM_BUCK_CTRL BIT(1)
#define MCUPM_ARMPLL_CTRL BIT(2)
#define MCUPM_CM_CTRL BIT(3)
#define MCUPM_PWR_CTRL_MASK (BIT(3) - 1)
/* Mbox Slot: APMCU_MCUPM_MBOX_L3_CACHE_MODE (5) */
#define MCUPM_L3_OFF_MODE (0) /* default */
#define MCUPM_L3_DORMANT_MODE (1)
#define NF_MCUPM_L3_MODE (2)
/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE (6) */
#define MCUPM_BUCK_NORMAL_MODE (0) /* default */
#define MCUPM_BUCK_LP_MODE (1)
#define MCUPM_BUCK_OFF_MODE (2)
#define NF_MCUPM_BUCK_MODE (3)
/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE (7) */
#define MCUPM_ARMPLL_ON (0) /* default */
#define MCUPM_ARMPLL_GATING (1)
#define MCUPM_ARMPLL_OFF (2)
#define NF_MCUPM_ARMPLL_MODE (3)
/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA (9) */
#define MCUPM_TASK_UNINIT (0)
#define MCUPM_TASK_INIT (1)
#define MCUPM_TASK_INIT_FINISH (2)
#define MCUPM_TASK_WAIT (3)
#define MCUPM_TASK_RUN (4)
#define MCUPM_TASK_PAUSE (5)
void mtk_set_mcupm_pll_mode(unsigned int mode);
int mtk_get_mcupm_pll_mode(void);
void mtk_set_mcupm_buck_mode(unsigned int mode);
int mtk_get_mcupm_buck_mode(void);
void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid);
unsigned int mtk_get_cpu_pm_preffered_cpu(void);
enum cpupm_mbox_depd_type {
CPUPM_MBOX_WAIT_DEV_INIT,
CPUPM_MBOX_WAIT_TASK_READY,
};
int mtk_lp_depd_condition(enum cpupm_mbox_depd_type type);
#endif /* MT_CPU_PM_MBOX_H */
@@ -0,0 +1,93 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <plat/common/platform.h>
#include <lib/pm/mtk_pm.h>
#include <mcucfg.h>
#include "mt_cpu_pm.h"
#include "mt_smp.h"
static inline int is_core_power_status_on(unsigned int cpuid)
{
return !!(mmio_read_32(CPU_PWR_STATUS) & BIT(cpuid));
}
void mt_smp_core_init_arch(unsigned int cluster, unsigned int cpu, int arm64,
struct cpu_pwr_ctrl *pwr_ctrl)
{
CPU_PM_ASSERT(cluster == 0);
CPU_PM_ASSERT(pwr_ctrl != NULL);
/* aa64naa32 in bits[16:23] */
if (arm64 != 0) {
mmio_setbits_32(pwr_ctrl->arch_addr, 1 << (16 + cpu));
} else {
mmio_clrbits_32(pwr_ctrl->arch_addr, 1 << (16 + cpu));
}
}
void mt_smp_core_bootup_address_set(struct cpu_pwr_ctrl *pwr_ctrl, uintptr_t entry)
{
CPU_PM_ASSERT(pwr_ctrl != NULL);
/* Set bootup address */
mmio_write_32(pwr_ctrl->rvbaraddr_l, entry);
}
int mt_smp_power_core_on(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl)
{
unsigned int val = is_core_power_status_on(cpu_id);
CPU_PM_ASSERT(pwr_ctrl);
mmio_clrbits_32(pwr_ctrl->pwpr, RESETPWRON_CONFIG);
if (val == 0) {
/*
* Set to 0 after BIG VPROC bulk powered on (configure in MCUPM) and
* before big core power-on sequence.
*/
if (cpu_id >= PLAT_CPU_PM_B_BUCK_ISO_ID) {
mmio_write_32(DREQ20_BIG_VPROC_ISO, 0);
}
mmio_setbits_32(pwr_ctrl->pwpr, PWR_RST_B);
dsbsy();
/* set mp0_spmc_pwr_on_cpuX = 1 */
mmio_setbits_32(pwr_ctrl->pwpr, PWR_ON);
val = 0;
while (is_core_power_status_on(cpu_id) == 0) {
DO_SMP_CORE_ON_WAIT_TIMEOUT(val);
mmio_clrbits_32(pwr_ctrl->pwpr, PWR_ON);
mmio_setbits_32(pwr_ctrl->pwpr, PWR_ON);
}
} else {
INFO("[%s:%d] - core_%u haven been power on\n", __func__, __LINE__, cpu_id);
}
return MTK_CPUPM_E_OK;
}
int mt_smp_power_core_off(struct cpu_pwr_ctrl *pwr_ctrl)
{
/* set mp0_spmc_pwr_on_cpuX = 1 */
mmio_clrbits_32(pwr_ctrl->pwpr, PWR_ON);
return MTK_CPUPM_E_OK;
}
void mt_smp_init(void)
{
/* clear RESETPWRON_CONFIG of mcusys/cluster/core0 */
mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
}
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SMP_H
#define MT_SMP_H
#include <lib/mmio.h>
#include <platform_def.h>
#define CPU_PWR_STATUS (MCUCFG_BASE + 0xA840)
#define SMP_CORE_TIMEOUT_MAX (50000)
#define DO_SMP_CORE_ON_WAIT_TIMEOUT(k_cnt) ({ \
CPU_PM_ASSERT(k_cnt < SMP_CORE_TIMEOUT_MAX); \
k_cnt++; udelay(1); })
void mt_smp_core_init_arch(unsigned int cluster, unsigned int cpu, int arm64,
struct cpu_pwr_ctrl *pwr_ctrl);
void mt_smp_core_bootup_address_set(struct cpu_pwr_ctrl *pwr_ctrl, uintptr_t entry);
int mt_smp_power_core_on(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl);
int mt_smp_power_core_off(struct cpu_pwr_ctrl *pwr_ctrl);
void mt_smp_init(void);
#endif /* MT_SMP_H */
@@ -0,0 +1,19 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := cpcv${CONFIG_MTK_CPU_PM_ARCH}
LOCAL_SRCS-y := ${LOCAL_DIR}/mt_cpu_pm.c ${LOCAL_DIR}/mt_cpu_pm_cpc.c
LOCAL_SRCS-$(CPU_PM_TINYSYS_SUPPORT) += ${LOCAL_DIR}/mt_cpu_pm_mbox.c
LOCAL_SRCS-$(CONFIG_MTK_SMP_EN) += ${LOCAL_DIR}/mt_smp.c
$(eval $(call add_defined_option,CPU_PM_TINYSYS_SUPPORT))
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,13 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := cpu_pm
SUB_RULES-${CONFIG_MTK_CPU_PM_SUPPORT} := $(LOCAL_DIR)/cpcv${CONFIG_MTK_CPU_PM_ARCH}
$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
@@ -0,0 +1,402 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <mtk_dcm_utils.h>
#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK BIT(17)
#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(15) | BIT(16) | BIT(17) | \
BIT(18) | BIT(21))
#define MP_CPUSYS_TOP_ADB_DCM_REG2_MASK (BIT(15) | BIT(16) | BIT(17) | BIT(18))
#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON BIT(17)
#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(15) | BIT(16) | BIT(17) | \
BIT(18) | BIT(21))
#define MP_CPUSYS_TOP_ADB_DCM_REG2_ON (BIT(15) | BIT(16) | BIT(17) | BIT(18))
#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF (0x0 << 17)
#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 15) | (0x0 << 16) | \
(0x0 << 17) | (0x0 << 18) | \
(0x0 << 21))
#define MP_CPUSYS_TOP_ADB_DCM_REG2_OFF ((0x0 << 15) | (0x0 << 16) | \
(0x0 << 17) | (0x0 << 18))
bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
{
bool ret = true;
ret &= dcm_check_state(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
ret &= dcm_check_state(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
ret &= dcm_check_state(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
return ret;
}
void dcm_mp_cpusys_top_adb_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
MP_CPUSYS_TOP_ADB_DCM_REG2_OFF);
}
}
#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK BIT(5)
#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK BIT(8)
#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK BIT(16)
#define MP_CPUSYS_TOP_APB_DCM_REG0_ON BIT(5)
#define MP_CPUSYS_TOP_APB_DCM_REG1_ON BIT(8)
#define MP_CPUSYS_TOP_APB_DCM_REG2_ON BIT(16)
#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF (0x0 << 5)
#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF (0x0 << 8)
#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF (0x0 << 16)
bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
{
bool ret = true;
ret &= dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
MP_CPUSYS_TOP_APB_DCM_REG0_ON);
ret &= dcm_check_state(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
MP_CPUSYS_TOP_APB_DCM_REG1_ON);
ret &= dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
MP_CPUSYS_TOP_APB_DCM_REG2_ON);
return ret;
}
void dcm_mp_cpusys_top_apb_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_apb_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
MP_CPUSYS_TOP_APB_DCM_REG0_ON);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
MP_CPUSYS_TOP_APB_DCM_REG1_ON);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
MP_CPUSYS_TOP_APB_DCM_REG2_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_apb_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
MP_CPUSYS_TOP_APB_DCM_REG2_OFF);
}
}
#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK (BIT(11) | BIT(24) | BIT(25))
#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11) | BIT(24) | BIT(25))
#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11) | \
(0x0 << 24) | \
(0x0 << 25))
bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK BIT(0)
#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON BIT(0)
#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF (0x0 << 0)
bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG7,
MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_core_stall_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_core_stall_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_core_stall_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK (0xffff << 0)
#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON (0xffff << 0)
#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF (0x0 << 0)
bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_MCSIC_DCM0,
MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_cpubiu_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK (BIT(24) | BIT(25))
#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(24) | BIT(25))
#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 24) | (0x0 << 25))
bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK (BIT(24) | BIT(25))
#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(24) | BIT(25))
#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 24) | (0x0 << 25))
bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK BIT(4)
#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON BIT(4)
#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF (0x0 << 4)
bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG7,
MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_fcm_stall_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_fcm_stall_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_fcm_stall_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK BIT(31)
#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON BIT(31)
#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF (0x0U << 31)
bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(1) | BIT(4))
#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(1) | BIT(4))
#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 1) | (0x0 << 4))
bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
{
return dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
}
void dcm_mp_cpusys_top_misc_dcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_misc_dcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
}
}
#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK BIT(3)
#define MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON BIT(3)
#define MP_CPUSYS_TOP_MP0_QDCM_REG1_ON (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 3))
#define MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF ((0x0 << 0) | (0x0 << 1) | \
(0x0 << 2) | (0x0 << 3))
bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
{
bool ret = true;
ret &= dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
ret &= dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG0,
MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
return ret;
}
void dcm_mp_cpusys_top_mp0_qdcm(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
} else {
/* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF);
}
}
#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | (0x0 << 1) | \
(0x0 << 2) | (0x0 << 3))
bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
{
return dcm_check_state(CPCCFG_REG_EMI_WFIFO,
CPCCFG_REG_EMI_WFIFO_REG0_MASK,
CPCCFG_REG_EMI_WFIFO_REG0_ON);
}
void dcm_cpccfg_reg_emi_wfifo(bool on)
{
if (on) {
/* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */
mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
CPCCFG_REG_EMI_WFIFO_REG0_MASK,
CPCCFG_REG_EMI_WFIFO_REG0_ON);
} else {
/* TINFO = "Turn OFF DCM 'cpccfg_reg_emi_wfifo'" */
mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
CPCCFG_REG_EMI_WFIFO_REG0_MASK,
CPCCFG_REG_EMI_WFIFO_REG0_OFF);
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MTK_DCM_UTILS_H
#define MTK_DCM_UTILS_H
#include <stdbool.h>
#include <mtk_dcm.h>
#include <platform_def.h>
/* Base */
#define MP_CPUSYS_TOP_BASE (MCUCFG_BASE + 0x8000)
#define CPCCFG_REG_BASE (MCUCFG_BASE + 0xA800)
/* Register Definition */
#define CPCCFG_REG_EMI_WFIFO (CPCCFG_REG_BASE + 0x100)
#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG0 (MP_CPUSYS_TOP_BASE + 0x22a0)
#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG1 (MP_CPUSYS_TOP_BASE + 0x22a4)
#define MP_CPUSYS_TOP_BUS_PLLDIV_CFG (MP_CPUSYS_TOP_BASE + 0x22e0)
#define MP_CPUSYS_TOP_MCSIC_DCM0 (MP_CPUSYS_TOP_BASE + 0x2440)
#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2500)
#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG4 (MP_CPUSYS_TOP_BASE + 0x2510)
#define MP_CPUSYS_TOP_MP_MISC_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2518)
#define MP_CPUSYS_TOP_MCUSYS_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x25c0)
#define MP_CPUSYS_TOP_MP0_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x4880)
#define MP_CPUSYS_TOP_MP0_DCM_CFG7 (MP_CPUSYS_TOP_BASE + 0x489c)
/* MP_CPUSYS_TOP */
bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
void dcm_mp_cpusys_top_adb_dcm(bool on);
bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
void dcm_mp_cpusys_top_apb_dcm(bool on);
bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
void dcm_mp_cpusys_top_core_stall_dcm(bool on);
bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
void dcm_mp_cpusys_top_misc_dcm(bool on);
bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
void dcm_mp_cpusys_top_mp0_qdcm(bool on);
/* CPCCFG_REG */
bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
void dcm_cpccfg_reg_emi_wfifo(bool on);
#endif
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/mtk_init/mtk_init.h>
#include <mtk_dcm.h>
#include <mtk_dcm_utils.h>
static void dcm_armcore(bool mode)
{
dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
}
static void dcm_mcusys(bool on)
{
dcm_mp_cpusys_top_adb_dcm(on);
dcm_mp_cpusys_top_apb_dcm(on);
dcm_mp_cpusys_top_cpubiu_dcm(on);
dcm_mp_cpusys_top_misc_dcm(on);
dcm_mp_cpusys_top_mp0_qdcm(on);
/* CPCCFG_REG */
dcm_cpccfg_reg_emi_wfifo(on);
dcm_mp_cpusys_top_last_cor_idle_dcm(on);
}
static void dcm_stall(bool on)
{
dcm_mp_cpusys_top_core_stall_dcm(on);
dcm_mp_cpusys_top_fcm_stall_dcm(on);
}
static bool check_dcm_state(void)
{
bool ret = true;
ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
return ret;
}
bool dcm_check_state(uintptr_t addr, unsigned int mask, unsigned int compare)
{
return ((mmio_read_32(addr) & mask) == compare);
}
int dcm_set_init(void)
{
int ret;
dcm_armcore(true);
dcm_mcusys(true);
dcm_stall(true);
if (check_dcm_state() == false) {
ERROR("Failed to set default dcm on!!\n");
ret = -1;
} else {
INFO("%s, dcm pass\n", __func__);
ret = 0;
}
return ret;
}
MTK_PLAT_SETUP_0_INIT(dcm_set_init);
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MTK_DCM_H
#define MTK_DCM_H
#include <stdbool.h>
bool dcm_check_state(uintptr_t addr, unsigned int mask, unsigned int compare);
int dcm_set_init(void);
#endif /* #ifndef MTK_DCM_H */
@@ -0,0 +1,17 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mtk_dcm
LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_dcm.c
LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtk_dcm_utils.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <dfd.h>
#include <mtk_sip_svc.h>
#include <plat_dfd.h>
static u_register_t dfd_smc_dispatcher(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3,
void *handle, struct smccc_res *smccc_ret)
{
int ret = MTK_SIP_E_SUCCESS;
switch (arg0) {
case PLAT_MTK_DFD_SETUP_MAGIC:
INFO("[%s] DFD setup call from kernel\n", __func__);
dfd_setup(arg1, arg2, arg3);
break;
case PLAT_MTK_DFD_READ_MAGIC:
/* only allow to access DFD register base + 0x200 */
if (arg1 <= 0x200) {
ret = mmio_read_32(MISC1_CFG_BASE + arg1);
}
break;
case PLAT_MTK_DFD_WRITE_MAGIC:
/* only allow to access DFD register base + 0x200 */
if (arg1 <= 0x200) {
sync_writel(MISC1_CFG_BASE + arg1, arg2);
}
break;
default:
ret = MTK_SIP_E_INVALID_PARAM;
break;
}
return ret;
}
DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_DFD, dfd_smc_dispatcher);
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DFD_H
#define DFD_H
#include <arch_helpers.h>
#include <lib/mmio.h>
void dfd_resume(void);
void dfd_setup(uint64_t base_addr, uint64_t chain_length, uint64_t cache_dump);
#endif /* DFD_H */
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <dfd.h>
#include <plat_dfd.h>
static uint64_t dfd_cache_dump;
static bool dfd_enabled;
static uint64_t dfd_base_addr;
static uint64_t dfd_chain_length;
void dfd_setup(uint64_t base_addr, uint64_t chain_length, uint64_t cache_dump)
{
mmio_write_32(MTK_DRM_LATCH_CTL1, MTK_DRM_LATCH_CTL1_VAL);
mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_VAL);
mmio_write_32(MTK_WDT_LATCH_CTL2, MTK_WDT_LATCH_CTL2_VAL);
mmio_clrbits_32(DFD_O_INTRF_MCU_PWR_CTL_MASK, BIT(2));
mmio_setbits_32(DFD_V50_GROUP_0_63_DIFF, 0x1);
sync_writel(DFD_INTERNAL_CTL, 0x5);
mmio_setbits_32(DFD_INTERNAL_CTL, BIT(13));
mmio_setbits_32(DFD_INTERNAL_CTL, 0x1F << 3);
mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 9);
mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 19);
mmio_write_32(DFD_INTERNAL_PWR_ON, 0xB);
mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0x0);
mmio_write_32(DFD_INTERNAL_TEST_SO_OVER_64, 0x1);
mmio_write_32(DFD_TEST_SI_0, 0x0);
mmio_write_32(DFD_TEST_SI_1, 0x0);
mmio_write_32(DFD_TEST_SI_2, 0x0);
mmio_write_32(DFD_TEST_SI_3, 0x0);
sync_writel(DFD_POWER_CTL, 0xF9);
sync_writel(DFD_READ_ADDR, DFD_READ_ADDR_VAL);
sync_writel(DFD_V30_CTL, 0xD);
mmio_write_32(DFD_O_SET_BASEADDR_REG, base_addr >> 24);
mmio_write_32(DFD_O_REG_0, 0);
/* setup global variables for suspend and resume */
dfd_enabled = true;
dfd_base_addr = base_addr;
dfd_chain_length = chain_length;
dfd_cache_dump = cache_dump;
if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_CACHE_VAL);
sync_writel(DFD_V35_ENABLE, 0x1);
sync_writel(DFD_V35_TAP_NUMBER, 0xB);
sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
/* Cache dump only mode */
sync_writel(DFD_V35_CTL, 0x1);
mmio_write_32(DFD_INTERNAL_NUM_OF_TEST_SO_GROUP, 0xF);
mmio_write_32(DFD_CHAIN_LENGTH0, DFD_CHAIN_LENGTH_VAL);
mmio_write_32(DFD_CHAIN_LENGTH1, DFD_CHAIN_LENGTH_VAL);
mmio_write_32(DFD_CHAIN_LENGTH2, DFD_CHAIN_LENGTH_VAL);
mmio_write_32(DFD_CHAIN_LENGTH3, DFD_CHAIN_LENGTH_VAL);
if ((cache_dump & DFD_PARITY_ERR_TRIGGER) != 0UL) {
sync_writel(DFD_HW_TRIGGER_MASK, 0xC);
mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 4);
}
}
dsbsy();
}
void dfd_resume(void)
{
if (dfd_enabled == true) {
dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLAT_DFD_H
#define PLAT_DFD_H
#include <lib/mmio.h>
#include <platform_def.h>
#define sync_writel(addr, val) do { mmio_write_32((addr), (val)); dsbsy(); } while (0)
#define PLAT_MTK_DFD_SETUP_MAGIC (0x99716150)
#define PLAT_MTK_DFD_READ_MAGIC (0x99716151)
#define PLAT_MTK_DFD_WRITE_MAGIC (0x99716152)
#define MTK_DRM_LATCH_CTL1 (DRM_BASE + 0x40)
#define MTK_DRM_LATCH_CTL2 (DRM_BASE + 0x44)
#define MTK_WDT_BASE (RGU_BASE)
#define MTK_WDT_INTERVAL (MTK_WDT_BASE + 0x10)
#define MTK_WDT_LATCH_CTL2 (MTK_WDT_BASE + 0x48)
#define MCU_BIU_BASE (MCUCFG_BASE)
#define MISC1_CFG_BASE (MCU_BIU_BASE + 0xE040)
#define DFD_INTERNAL_CTL (MISC1_CFG_BASE + 0x00)
#define DFD_INTERNAL_PWR_ON (MISC1_CFG_BASE + 0x08)
#define DFD_CHAIN_LENGTH0 (MISC1_CFG_BASE + 0x0C)
#define DFD_INTERNAL_SHIFT_CLK_RATIO (MISC1_CFG_BASE + 0x10)
#define DFD_CHAIN_LENGTH1 (MISC1_CFG_BASE + 0x1C)
#define DFD_CHAIN_LENGTH2 (MISC1_CFG_BASE + 0x20)
#define DFD_CHAIN_LENGTH3 (MISC1_CFG_BASE + 0x24)
#define DFD_INTERNAL_TEST_SO_0 (MISC1_CFG_BASE + 0x28)
#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP (MISC1_CFG_BASE + 0x30)
#define DFD_INTERNAL_TEST_SO_OVER_64 (MISC1_CFG_BASE + 0x34)
#define DFD_INTERNAL_SW_NS_TRIGGER (MISC1_CFG_BASE + 0x3c)
#define DFD_V30_CTL (MISC1_CFG_BASE + 0x48)
#define DFD_V30_BASE_ADDR (MISC1_CFG_BASE + 0x4C)
#define DFD_POWER_CTL (MISC1_CFG_BASE + 0x50)
#define DFD_TEST_SI_0 (MISC1_CFG_BASE + 0x58)
#define DFD_TEST_SI_1 (MISC1_CFG_BASE + 0x5C)
#define DFD_CLEAN_STATUS (MISC1_CFG_BASE + 0x60)
#define DFD_TEST_SI_2 (MISC1_CFG_BASE + 0x1D8)
#define DFD_TEST_SI_3 (MISC1_CFG_BASE + 0x1DC)
#define DFD_READ_ADDR (MISC1_CFG_BASE + 0x1E8)
#define DFD_HW_TRIGGER_MASK (MISC1_CFG_BASE + 0xBC)
#define DFD_V35_ENABLE (MCU_BIU_BASE + 0xE0A8)
#define DFD_V35_TAP_NUMBER (MCU_BIU_BASE + 0xE0AC)
#define DFD_V35_TAP_EN (MCU_BIU_BASE + 0xE0B0)
#define DFD_V35_CTL (MCU_BIU_BASE + 0xE0B4)
#define DFD_V35_SEQ0_0 (MCU_BIU_BASE + 0xE0C0)
#define DFD_V35_SEQ0_1 (MCU_BIU_BASE + 0xE0C4)
#define DFD_V50_GROUP_0_63_DIFF (MCU_BIU_BASE + 0xE2AC)
#define DFD_O_PROTECT_EN_REG (0x10001220)
#define DFD_O_INTRF_MCU_PWR_CTL_MASK (0x10001A3C)
#define DFD_O_SET_BASEADDR_REG (0x10043000)
#define DFD_O_REG_0 (0x10001390)
#define DFD_CACHE_DUMP_ENABLE (1U)
#define DFD_PARITY_ERR_TRIGGER (2U)
#define DFD_V35_TAP_EN_VAL (0x43FF)
#define DFD_V35_SEQ0_0_VAL (0x63668820)
#define DFD_READ_ADDR_VAL (0x40000008)
#define DFD_CHAIN_LENGTH_VAL (0xFFFFFFFF)
#define MTK_WDT_LATCH_CTL2_VAL (0x9507FFFF)
#define MTK_WDT_INTERVAL_VAL (0x6600000A)
#define MTK_DRM_LATCH_CTL2_VAL (0x950607D0)
#define MTK_DRM_LATCH_CTL2_CACHE_VAL (0x95065DC0)
#define MTK_DRM_LATCH_CTL1_VAL (0x95000013)
#endif /* PLAT_DFD_H */
@@ -0,0 +1,17 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mtk_dfd
LOCAL_SRCS-y := ${LOCAL_DIR}/dfd.c
LOCAL_SRCS-y += ${LOCAL_DIR}/$(MTK_SOC)/plat_dfd.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <inttypes.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <mt_dp.h>
#include <mtk_sip_svc.h>
#include <platform_def.h>
static uint32_t dp_write_sec_reg(uint32_t is_edp, uint32_t offset,
uint32_t value, uint32_t mask)
{
uint32_t reg = (is_edp != 0U) ? EDP_SEC_BASE : DP_SEC_BASE;
mmio_clrsetbits_32(reg + offset, mask, value);
return mmio_read_32(reg + offset);
}
int32_t dp_secure_handler(uint64_t cmd, uint64_t para, uint32_t *val)
{
int32_t ret = 0L;
uint32_t is_edp = 0UL;
uint32_t regval = 0UL;
uint32_t regmsk = 0UL;
uint32_t fldmask = 0UL;
if ((cmd > DP_ATF_CMD_COUNT) || (val == NULL)) {
INFO("dp_secure_handler error cmd 0x%" PRIx64 "\n", cmd);
return MTK_SIP_E_INVALID_PARAM;
}
switch (cmd) {
case DP_ATF_DP_VIDEO_UNMUTE:
INFO("[%s] DP_ATF_DP_VIDEO_UNMUTE\n", __func__);
is_edp = DP_ATF_TYPE_DP;
ret = MTK_SIP_E_SUCCESS;
break;
case DP_ATF_EDP_VIDEO_UNMUTE:
INFO("[%s] DP_ATF_EDP_VIDEO_UNMUTE\n", __func__);
is_edp = DP_ATF_TYPE_EDP;
ret = MTK_SIP_E_SUCCESS;
break;
default:
ret = MTK_SIP_E_INVALID_PARAM;
break;
}
if (ret == MTK_SIP_E_SUCCESS) {
regmsk = (VIDEO_MUTE_SEL_SECURE_FLDMASK |
VIDEO_MUTE_SW_SECURE_FLDMASK);
if (para > 0U) {
fldmask = VIDEO_MUTE_SW_SECURE_FLDMASK;
} else {
fldmask = 0;
}
regval = (VIDEO_MUTE_SEL_SECURE_FLDMASK | fldmask);
*val = dp_write_sec_reg(is_edp, DP_TX_SECURE_REG11,
regval, regmsk);
}
return ret;
}
u_register_t mtk_dp_sip_handler(u_register_t x1, u_register_t x2,
u_register_t x3, u_register_t x4,
void *handle, struct smccc_res *smccc_ret)
{
uint32_t ret_val;
return dp_secure_handler(x1, x2, &ret_val);
}
DECLARE_SMC_HANDLER(MTK_SIP_DP_CONTROL, mtk_dp_sip_handler);
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_DP_H
#define MT_DP_H
#define DP_TX_SECURE_REG11 (0x2c)
#define VIDEO_MUTE_SEL_SECURE_FLDMASK (0x10)
#define VIDEO_MUTE_SW_SECURE_FLDMASK (0x8)
enum DP_ATF_HW_TYPE {
DP_ATF_TYPE_DP = 0,
DP_ATF_TYPE_EDP = 1
};
enum DP_ATF_CMD {
DP_ATF_DP_VIDEO_UNMUTE = 0x20,
DP_ATF_EDP_VIDEO_UNMUTE,
DP_ATF_CMD_COUNT
};
int32_t dp_secure_handler(uint64_t cmd, uint64_t para, uint32_t *val);
#endif
@@ -0,0 +1,14 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := dp
LOCAL_SRCS-y := $(LOCAL_DIR)/mt_dp.c
PLAT_INCLUDES += -I${LOCAL_DIR}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef EMI_MPU_H
#define EMI_MPU_H
#include <emi_mpu_priv.h>
#include <platform_def.h>
#define NO_PROTECTION (0)
#define SEC_RW (1)
#define SEC_RW_NSEC_R (2)
#define SEC_RW_NSEC_W (3)
#define SEC_R_NSEC_R (4)
#define FORBIDDEN (5)
#define SEC_R_NSEC_RW (6)
#define LOCK (1)
#define UNLOCK (0)
#if (EMI_MPU_DGROUP_NUM == 1)
#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
do { \
apc_ary[1] = 0; \
apc_ary[0] = \
(((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
(((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
(((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
(((unsigned int) d1) << 3) | ((unsigned int) d0) | \
((unsigned int) lock << 31); \
} while (0)
#elif (EMI_MPU_DGROUP_NUM == 2)
#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
do { \
apc_ary[1] = \
(((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) | \
(((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) | \
(((unsigned int) d11) << 9) | (((unsigned int) d10) << 6) | \
(((unsigned int) d9) << 3) | ((unsigned int) d8); \
apc_ary[0] = \
(((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
(((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
(((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
(((unsigned int) d1) << 3) | ((unsigned int) d0) | \
((unsigned int) lock << 31); \
} while (0)
#endif
struct emi_region_info_t {
unsigned long long start;
unsigned long long end;
unsigned int region;
unsigned int apc[EMI_MPU_DGROUP_NUM];
};
int emi_mpu_init(void);
int emi_mpu_set_protection(struct emi_region_info_t *region_info);
void set_emi_mpu_regions(void);
#endif
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <emi_mpu.h>
#include <lib/mtk_init/mtk_init.h>
#if ENABLE_EMI_MPU_SW_LOCK
static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
#endif
#define EMI_MPU_START_MASK (0x00FFFFFF)
#define EMI_MPU_END_MASK (0x00FFFFFF)
#define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF)
#define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF)
static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
unsigned int apc)
{
unsigned int dgroup;
unsigned int region;
region = (start >> 24) & 0xFF;
start &= EMI_MPU_START_MASK;
dgroup = (end >> 24) & 0xFF;
end &= EMI_MPU_END_MASK;
if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
WARN("invalid region, domain\n");
return -1;
}
#if ENABLE_EMI_MPU_SW_LOCK
if (region_lock_state[region] == 1) {
WARN("invalid region\n");
return -1;
}
if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
region_lock_state[region] = 1;
}
apc &= EMI_MPU_APC_SW_LOCK_MASK;
#else
apc &= EMI_MPU_APC_HW_LOCK_MASK;
#endif
if ((start >= DRAM_OFFSET) && (end >= start)) {
start -= DRAM_OFFSET;
end -= DRAM_OFFSET;
} else {
WARN("invalid range\n");
return -1;
}
mmio_write_32(EMI_MPU_SA(region), start);
mmio_write_32(EMI_MPU_EA(region), end);
mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
#if defined(SUB_EMI_MPU_BASE)
mmio_write_32(SUB_EMI_MPU_SA(region), start);
mmio_write_32(SUB_EMI_MPU_EA(region), end);
mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
#endif
return 0;
}
static void dump_emi_mpu_regions(void)
{
int region, i;
/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
for (region = 0; region < 8; ++region) {
INFO("region %d:\n", region);
INFO("\tsa: 0x%x, ea: 0x%x\n",
mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
}
}
}
int emi_mpu_set_protection(struct emi_region_info_t *region_info)
{
unsigned int start, end;
int i;
if (region_info->region >= EMI_MPU_REGION_NUM) {
WARN("invalid region\n");
return -1;
}
start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
(region_info->region << 24);
for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
start, end, region_info->apc[i]);
}
}
return 0;
}
int emi_mpu_init(void)
{
INFO("[%s] emi mpu initialization\n", __func__);
set_emi_mpu_regions();
dump_emi_mpu_regions();
return 0;
}
MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <emi_mpu.h>
void set_emi_mpu_regions(void)
{
/* TODO: set emi mpu region */
INFO("%s, emi mpu is not setting currently\n", __func__);
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef EMI_MPU_PRIV_H
#define EMI_MPU_PRIV_H
#define ENABLE_EMI_MPU_SW_LOCK (1)
#define EMI_MPU_CTRL (EMI_MPU_BASE + 0x000)
#define EMI_MPU_DBG (EMI_MPU_BASE + 0x004)
#define EMI_MPU_SA0 (EMI_MPU_BASE + 0x100)
#define EMI_MPU_EA0 (EMI_MPU_BASE + 0x200)
#define EMI_MPU_SA(region) (EMI_MPU_SA0 + (region * 4))
#define EMI_MPU_EA(region) (EMI_MPU_EA0 + (region * 4))
#define EMI_MPU_APC0 (EMI_MPU_BASE + 0x300)
#define EMI_MPU_APC(region, dgroup) (EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
#define EMI_MPU_CTRL_D0 (EMI_MPU_BASE + 0x800)
#define EMI_MPU_CTRL_D(domain) (EMI_MPU_CTRL_D0 + (domain * 4))
#define EMI_RG_MASK_D0 (EMI_MPU_BASE + 0x900)
#define EMI_RG_MASK_D(domain) (EMI_RG_MASK_D0 + (domain * 4))
#define SUB_EMI_MPU_CTRL (SUB_EMI_MPU_BASE + 0x000)
#define SUB_EMI_MPU_DBG (SUB_EMI_MPU_BASE + 0x004)
#define SUB_EMI_MPU_SA0 (SUB_EMI_MPU_BASE + 0x100)
#define SUB_EMI_MPU_EA0 (SUB_EMI_MPU_BASE + 0x200)
#define SUB_EMI_MPU_SA(region) (SUB_EMI_MPU_SA0 + (region * 4))
#define SUB_EMI_MPU_EA(region) (SUB_EMI_MPU_EA0 + (region * 4))
#define SUB_EMI_MPU_APC0 (SUB_EMI_MPU_BASE + 0x300)
#define SUB_EMI_MPU_APC(region, dgroup) (SUB_EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
#define SUB_EMI_MPU_CTRL_D0 (SUB_EMI_MPU_BASE + 0x800)
#define SUB_EMI_MPU_CTRL_D(domain) (SUB_EMI_MPU_CTRL_D0 + (domain * 4))
#define SUB_EMI_RG_MASK_D0 (SUB_EMI_MPU_BASE + 0x900)
#define SUB_EMI_RG_MASK_D(domain) (SUB_EMI_RG_MASK_D0 + (domain * 4))
#define EMI_MPU_DOMAIN_NUM (16)
#define EMI_MPU_REGION_NUM (32)
#define EMI_MPU_ALIGN_BITS (16)
#define DRAM_OFFSET (0x40000000 >> EMI_MPU_ALIGN_BITS)
#define EMI_MPU_DGROUP_NUM (EMI_MPU_DOMAIN_NUM / 8)
#endif
@@ -0,0 +1,16 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := emi_mpu
LOCAL_SRCS-y := $(LOCAL_DIR)/emi_mpu_common.c
LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/emi_mpu.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,208 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "../drivers/arm/gic/v3/gicv3_private.h"
#include <bl31/interrupt_mgmt.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <lib/mtk_init/mtk_init.h>
#include <mt_gic_v3.h>
#include <mtk_plat_common.h>
#include <plat/common/platform.h>
#include <plat_private.h>
#include <platform_def.h>
#define SGI_MASK 0xffff
uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
static uint32_t rdist_has_saved[PLATFORM_CORE_COUNT];
/* we save and restore the GICv3 context on system suspend */
gicv3_dist_ctx_t dist_ctx;
static unsigned int mt_mpidr_to_core_pos(u_register_t mpidr)
{
return plat_core_pos_by_mpidr(mpidr);
}
gicv3_driver_data_t mt_gicv3_data = {
.gicd_base = MT_GIC_BASE,
.gicr_base = MT_GIC_RDIST_BASE,
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = rdistif_base_addrs,
.mpidr_to_core_pos = mt_mpidr_to_core_pos,
};
struct gic_chip_data {
/* All cores share the same configuration */
unsigned int saved_group;
unsigned int saved_enable;
unsigned int saved_conf0;
unsigned int saved_conf1;
unsigned int saved_grpmod;
/* Per-core sgi */
unsigned int saved_sgi[PLATFORM_CORE_COUNT];
};
static struct gic_chip_data gic_data;
void mt_gic_driver_init(void)
{
gicv3_driver_init(&mt_gicv3_data);
}
void mt_gic_set_pending(uint32_t irq)
{
gicv3_set_interrupt_pending(irq, plat_my_core_pos());
}
void mt_gic_distif_save(void)
{
gicv3_distif_save(&dist_ctx);
}
void mt_gic_distif_restore(void)
{
gicv3_distif_init_restore(&dist_ctx);
}
void mt_gic_rdistif_init(void)
{
unsigned int proc_num;
unsigned int index;
uintptr_t gicr_base;
proc_num = plat_my_core_pos();
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
/* set all SGI/PPI as non-secure GROUP1 by default */
mmio_write_32(gicr_base + GICR_IGROUPR0, ~0U);
mmio_write_32(gicr_base + GICR_IGRPMODR0, 0x0);
/* setup the default PPI/SGI priorities */
for (index = 0; index < TOTAL_PCPU_INTR_NUM; index += 4U)
gicr_write_ipriorityr(gicr_base, index,
GICD_IPRIORITYR_DEF_VAL);
}
void mt_gic_rdistif_save(void)
{
unsigned int proc_num;
uintptr_t gicr_base;
proc_num = plat_my_core_pos();
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
gic_data.saved_group = mmio_read_32(gicr_base + GICR_IGROUPR0);
gic_data.saved_enable = mmio_read_32(gicr_base + GICR_ISENABLER0);
gic_data.saved_conf0 = mmio_read_32(gicr_base + GICR_ICFGR0);
gic_data.saved_conf1 = mmio_read_32(gicr_base + GICR_ICFGR1);
gic_data.saved_grpmod = mmio_read_32(gicr_base + GICR_IGRPMODR0);
rdist_has_saved[proc_num] = 1;
}
void mt_gic_rdistif_restore(void)
{
unsigned int proc_num;
uintptr_t gicr_base;
proc_num = plat_my_core_pos();
if (rdist_has_saved[proc_num] == 1) {
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
mmio_write_32(gicr_base + GICR_IGROUPR0, gic_data.saved_group);
mmio_write_32(gicr_base + GICR_ISENABLER0,
gic_data.saved_enable);
mmio_write_32(gicr_base + GICR_ICFGR0, gic_data.saved_conf0);
mmio_write_32(gicr_base + GICR_ICFGR1, gic_data.saved_conf1);
mmio_write_32(gicr_base + GICR_IGRPMODR0,
gic_data.saved_grpmod);
}
}
void mt_gic_rdistif_restore_all(void)
{
unsigned int proc_num;
uintptr_t gicr_base;
for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) {
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
mmio_write_32(gicr_base + GICR_IGROUPR0, gic_data.saved_group);
mmio_write_32(gicr_base + GICR_ISENABLER0,
gic_data.saved_enable);
mmio_write_32(gicr_base + GICR_ICFGR0, gic_data.saved_conf0);
mmio_write_32(gicr_base + GICR_ICFGR1, gic_data.saved_conf1);
mmio_write_32(gicr_base + GICR_IGRPMODR0,
gic_data.saved_grpmod);
}
}
void gic_sgi_save_all(void)
{
unsigned int proc_num;
uintptr_t gicr_base;
for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) {
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
gic_data.saved_sgi[proc_num] =
mmio_read_32(gicr_base + GICR_ISPENDR0) & SGI_MASK;
}
}
void gic_sgi_restore_all(void)
{
unsigned int proc_num;
uintptr_t gicr_base;
for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) {
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
mmio_write_32(gicr_base + GICR_ICPENDR0, SGI_MASK);
mmio_write_32(gicr_base + GICR_ISPENDR0,
gic_data.saved_sgi[proc_num] & SGI_MASK);
}
}
void mt_gic_init(void)
{
gicv3_distif_init();
gicv3_rdistif_init(plat_my_core_pos());
gicv3_cpuif_enable(plat_my_core_pos());
}
uint32_t mt_irq_get_pending(uint32_t irq)
{
uint32_t val;
val = mmio_read_32(BASE_GICD_BASE + GICD_ISPENDR +
irq / 32 * 4);
val = (val >> (irq % 32)) & 1U;
return val;
}
void mt_irq_set_pending(uint32_t irq)
{
uint32_t bit = 1U << (irq % 32);
mmio_write_32(BASE_GICD_BASE + GICD_ISPENDR +
irq / 32 * 4, bit);
}
int mt_gic_one_init(void)
{
INFO("[%s] GIC initialization\n", __func__);
/* Initialize the GIC driver, CPU and distributor interfaces */
mt_gic_driver_init();
mt_gic_init();
return 0;
}
MTK_PLAT_SETUP_0_INIT(mt_gic_one_init);
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_GIC_V3_H
#define MT_GIC_V3_H
#include <drivers/arm/gicv3.h>
#include <lib/mmio.h>
void mt_gic_driver_init(void);
void mt_gic_init(void);
void mt_gic_set_pending(uint32_t irq);
void mt_gic_distif_save(void);
void mt_gic_distif_restore(void);
void mt_gic_rdistif_init(void);
void mt_gic_rdistif_save(void);
void mt_gic_rdistif_restore(void);
void mt_gic_rdistif_restore_all(void);
void gic_sgi_save_all(void);
void gic_sgi_restore_all(void);
uint32_t mt_irq_get_pending(uint32_t irq);
void mt_irq_set_pending(uint32_t irq);
int mt_gic_one_init(void);
#endif /* MT_GIC_V3_H */
@@ -0,0 +1,14 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := gic600
LOCAL_SRCS-y := $(LOCAL_DIR)/mt_gic_v3.c
PLAT_INCLUDES += -I${LOCAL_DIR}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <mtgpio.h>
#include <platform_def.h>
uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
{
uintptr_t reg_addr = 0U;
struct mt_pin_info gpio_info;
assert(pin < MAX_GPIO_PIN);
gpio_info = mt_pin_infos[pin];
switch (gpio_info.base & 0x0f) {
case 0:
reg_addr = IOCFG_RM_BASE;
break;
case 1:
reg_addr = IOCFG_LT_BASE;
break;
case 2:
reg_addr = IOCFG_LM_BASE;
break;
case 3:
reg_addr = IOCFG_RT_BASE;
break;
default:
break;
}
return reg_addr;
}
@@ -0,0 +1,221 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_GPIO_H
#define MT_GPIO_H
#include <mtgpio_common.h>
/* Enumeration for GPIO pin */
typedef enum GPIO_PIN {
GPIO_UNSUPPORTED = -1,
GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, GPIO6,
GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13, GPIO14,
GPIO15, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22,
GPIO23, GPIO24, GPIO25, GPIO26, GPIO27, GPIO28, GPIO29, GPIO30,
GPIO31, GPIO32, GPIO33, GPIO34, GPIO35, GPIO36, GPIO37, GPIO38,
GPIO39, GPIO40, GPIO41, GPIO42, GPIO43, GPIO44, GPIO45, GPIO46,
GPIO47, GPIO48, GPIO49, GPIO50, GPIO51, GPIO52, GPIO53, GPIO54,
GPIO55, GPIO56, GPIO57, GPIO58, GPIO59, GPIO60, GPIO61, GPIO62,
GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70,
GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78,
GPIO79, GPIO80, GPIO81, GPIO82, GPIO83, GPIO84, GPIO85, GPIO86,
GPIO87, GPIO88, GPIO89, GPIO90, GPIO91, GPIO92, GPIO93, GPIO94,
GPIO95, GPIO96, GPIO97, GPIO98, GPIO99, GPIO100, GPIO101, GPIO102,
GPIO103, GPIO104, GPIO105, GPIO106, GPIO107, GPIO108, GPIO109, GPIO110,
GPIO111, GPIO112, GPIO113, GPIO114, GPIO115, GPIO116, GPIO117, GPIO118,
GPIO119, GPIO120, GPIO121, GPIO122, GPIO123, GPIO124, GPIO125, GPIO126,
GPIO127, GPIO128, GPIO129, GPIO130, GPIO131, GPIO132, GPIO133, GPIO134,
GPIO135, GPIO136, GPIO137, GPIO138, GPIO139, GPIO140, GPIO141, GPIO142,
GPIO143, GPIO144, GPIO145, GPIO146, GPIO147, GPIO148, GPIO149, GPIO150,
GPIO151, GPIO152, GPIO153, GPIO154, GPIO155, GPIO156, GPIO157, GPIO158,
GPIO159, GPIO160, GPIO161, GPIO162, GPIO163, GPIO164, GPIO165, GPIO166,
GPIO167, GPIO168, GPIO169, GPIO170, GPIO171, GPIO172, GPIO173, GPIO174,
GPIO175, GPIO176,
MT_GPIO_BASE_MAX
} GPIO_PIN;
static const struct mt_pin_info mt_pin_infos[] = {
PIN(0, 0, 6, 0x30, 0xb0),
PIN(1, 0, 7, 0x30, 0xb0),
PIN(2, 0, 8, 0x30, 0xb0),
PIN(3, 0, 9, 0x30, 0xb0),
PIN(4, 0, 10, 0x30, 0xb0),
PIN(5, 0, 11, 0x30, 0xb0),
PIN(6, 0, 12, 0x30, 0xb0),
PIN(7, 0, 13, 0x30, 0xb0),
PIN(8, 0, 14, 0x30, 0xb0),
PIN(9, 0, 15, 0x30, 0xb0),
PIN(10, 0, 16, 0x30, 0xb0),
PIN(11, 0, 17, 0x30, 0xb0),
PIN(12, 0, 12, 0x31, 0xa0),
PIN(13, 0, 13, 0x31, 0xa0),
PIN(14, 0, 14, 0x31, 0xa0),
PIN(15, 0, 15, 0x31, 0xa0),
PIN(16, 0, 1, 0x22, 0x50),
PIN(17, 0, 2, 0x22, 0x50),
PIN(18, 0, 3, 0x23, 0x60),
PIN(19, 0, 4, 0x23, 0x60),
PIN(20, 0, 5, 0x23, 0x60),
PIN(21, 0, 6, 0x23, 0x60),
PIN(22, 0, 0, 0x23, 0x60),
PIN(23, 0, 1, 0x23, 0x60),
PIN(24, 0, 2, 0x23, 0x60),
PIN(25, 0, 3, 0x30, 0xb0),
PIN(26, 0, 2, 0x30, 0xb0),
PIN(27, 0, 5, 0x30, 0xb0),
PIN(28, 0, 4, 0x30, 0xb0),
PIN(29, 0, 0, 0x30, 0xb0),
PIN(30, 0, 1, 0x30, 0xb0),
PIN(31, 0, 11, 0x30, 0xc0),
PIN(32, 0, 10, 0x30, 0xc0),
PIN(33, 0, 13, 0x30, 0xc0),
PIN(34, 0, 12, 0x30, 0xc0),
PIN(35, 0, 15, 0x30, 0xc0),
PIN(36, 0, 14, 0x30, 0xc0),
PIN(37, 0, 21, 0x30, 0xb0),
PIN(38, 0, 18, 0x30, 0xb0),
PIN(39, 0, 19, 0x30, 0xb0),
PIN(40, 0, 20, 0x30, 0xb0),
PIN(41, 0, 22, 0x30, 0xb0),
PIN(42, 1, 12, 0x31, 0xc0),
PIN(43, 1, 13, 0x31, 0xc0),
PIN(44, 1, 14, 0x31, 0xc0),
PIN(45, 1, 15, 0x31, 0xc0),
PIN(46, 0, 0, 0x22, 0x50),
PIN(47, 0, 25, 0x30, 0xb0),
PIN(48, 0, 24, 0x30, 0xb0),
PIN(49, 0, 23, 0x30, 0xb0),
PIN(50, 0, 5, 0x22, 0x50),
PIN(51, 0, 4, 0x22, 0x50),
PIN(52, 0, 3, 0x22, 0x50),
PIN(53, 0, 6, 0x22, 0x50),
PIN(54, 0, 7, 0x22, 0x50),
PIN(55, 0, 26, 0x30, 0xb0),
PIN(56, 0, 29, 0x30, 0xb0),
PIN(57, 0, 6, 0x31, 0xb0),
PIN(58, 0, 9, 0x31, 0xb0),
PIN(59, 0, 27, 0x30, 0xb0),
PIN(60, 0, 30, 0x30, 0xb0),
PIN(61, 0, 28, 0x30, 0xb0),
PIN(62, 0, 31, 0x30, 0xb0),
PIN(63, 0, 7, 0x31, 0xb0),
PIN(64, 0, 10, 0x31, 0xb0),
PIN(65, 0, 7, 0x23, 0x60),
PIN(66, 0, 9, 0x23, 0x60),
PIN(67, 0, 8, 0x23, 0x60),
PIN(68, 0, 10, 0x23, 0x60),
PIN(69, 0, 1, 0x30, 0xc0),
PIN(70, 0, 0, 0x30, 0xc0),
PIN(71, 0, 5, 0x30, 0xc0),
PIN(72, 0, 4, 0x30, 0xc0),
PIN(73, 0, 2, 0x30, 0xc0),
PIN(74, 0, 3, 0x30, 0xc0),
PIN(75, 0, 7, 0x30, 0xc0),
PIN(76, 0, 6, 0x30, 0xc0),
PIN(77, 0, 9, 0x30, 0xc0),
PIN(78, 0, 8, 0x30, 0xc0),
PIN(79, 0, 12, 0x23, 0x60),
PIN(80, 0, 11, 0x23, 0x60),
PIN(81, 0, 14, 0x23, 0x60),
PIN(82, 0, 13, 0x23, 0x60),
PIN(83, 0, 16, 0x31, 0xb0),
PIN(84, 0, 15, 0x31, 0xb0),
PIN(85, 0, 17, 0x31, 0xb0),
PIN(86, 0, 19, 0x31, 0xb0),
PIN(87, 0, 18, 0x31, 0xb0),
PIN(88, 0, 20, 0x31, 0xb0),
PIN(89, 0, 22, 0x31, 0xb0),
PIN(90, 0, 21, 0x31, 0xb0),
PIN(91, 0, 23, 0x31, 0xb0),
PIN(92, 0, 3, 0x31, 0xb0),
PIN(93, 0, 2, 0x31, 0xb0),
PIN(94, 0, 5, 0x31, 0xb0),
PIN(95, 0, 4, 0x31, 0xb0),
PIN(96, 0, 31, 0x31, 0xa0),
PIN(97, 0, 0, 0x31, 0xb0),
PIN(98, 0, 8, 0x31, 0xb0),
PIN(99, 0, 30, 0x31, 0xa0),
PIN(100, 0, 1, 0x31, 0xb0),
PIN(101, 0, 0, 0x31, 0xa0),
PIN(102, 0, 5, 0x31, 0xa0),
PIN(103, 0, 3, 0x31, 0xa0),
PIN(104, 0, 4, 0x31, 0xa0),
PIN(105, 0, 1, 0x31, 0xa0),
PIN(106, 0, 2, 0x31, 0xa0),
PIN(107, 0, 21, 0x31, 0xa0),
PIN(108, 0, 16, 0x31, 0xa0),
PIN(109, 0, 22, 0x31, 0xa0),
PIN(110, 0, 17, 0x31, 0xa0),
PIN(111, 0, 18, 0x31, 0xa0),
PIN(112, 0, 19, 0x31, 0xa0),
PIN(113, 0, 20, 0x31, 0xa0),
PIN(114, 0, 28, 0x31, 0xa0),
PIN(115, 0, 23, 0x31, 0xa0),
PIN(116, 0, 29, 0x31, 0xa0),
PIN(117, 0, 24, 0x31, 0xa0),
PIN(118, 0, 25, 0x31, 0xa0),
PIN(119, 0, 26, 0x31, 0xa0),
PIN(120, 0, 27, 0x31, 0xa0),
PIN(121, 0, 8, 0x22, 0x50),
PIN(122, 0, 11, 0x22, 0x50),
PIN(123, 0, 10, 0x22, 0x50),
PIN(124, 0, 9, 0x22, 0x50),
PIN(125, 0, 6, 0x31, 0xa0),
PIN(126, 0, 7, 0x31, 0xa0),
PIN(127, 0, 8, 0x31, 0xa0),
PIN(128, 0, 9, 0x31, 0xa0),
PIN(129, 0, 10, 0x31, 0xa0),
PIN(130, 0, 11, 0x31, 0xa0),
PIN(131, 1, 1, 0x30, 0xd0),
PIN(132, 1, 2, 0x30, 0xd0),
PIN(133, 1, 9, 0x30, 0xd0),
PIN(134, 1, 10, 0x30, 0xd0),
PIN(135, 1, 11, 0x30, 0xd0),
PIN(136, 1, 12, 0x30, 0xd0),
PIN(137, 1, 13, 0x30, 0xd0),
PIN(138, 1, 14, 0x30, 0xd0),
PIN(139, 1, 15, 0x30, 0xd0),
PIN(140, 1, 16, 0x30, 0xd0),
PIN(141, 1, 3, 0x30, 0xd0),
PIN(142, 1, 4, 0x30, 0xd0),
PIN(143, 1, 5, 0x30, 0xd0),
PIN(144, 1, 6, 0x30, 0xd0),
PIN(145, 1, 7, 0x30, 0xd0),
PIN(146, 1, 8, 0x30, 0xd0),
PIN(147, 1, 18, 0x30, 0xd0),
PIN(148, 1, 19, 0x30, 0xd0),
PIN(149, 1, 17, 0x30, 0xd0),
PIN(150, 1, 0, 0x30, 0xd0),
PIN(151, 1, 9, 0x31, 0xc0),
PIN(152, 1, 8, 0x31, 0xc0),
PIN(153, 1, 7, 0x31, 0xc0),
PIN(154, 1, 6, 0x31, 0xc0),
PIN(155, 1, 11, 0x31, 0xc0),
PIN(156, 1, 1, 0x31, 0xc0),
PIN(157, 1, 0, 0x31, 0xc0),
PIN(158, 1, 5, 0x31, 0xc0),
PIN(159, 1, 4, 0x31, 0xc0),
PIN(160, 1, 3, 0x31, 0xc0),
PIN(161, 1, 2, 0x31, 0xc0),
PIN(162, 1, 10, 0x31, 0xc0),
PIN(163, 1, 1, 0x23, 0x70),
PIN(164, 1, 0, 0x23, 0x70),
PIN(165, 1, 2, 0x23, 0x70),
PIN(166, 1, 3, 0x23, 0x70),
PIN(167, 1, 4, 0x23, 0x70),
PIN(168, 1, 5, 0x23, 0x70),
PIN(169, 1, 1, 0x22, 0x60),
PIN(170, 1, 0, 0x22, 0x60),
PIN(171, 1, 2, 0x22, 0x60),
PIN(172, 1, 3, 0x22, 0x60),
PIN(173, 1, 4, 0x22, 0x60),
PIN(174, 1, 5, 0x22, 0x60),
PIN(175, 0, 11, 0x31, 0xb0),
PIN(176, 0, 12, 0x31, 0xb0),
};
#endif /* MT_GPIO_H */
@@ -0,0 +1,302 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/gpio.h>
#include <lib/mmio.h>
#include <lib/mtk_init/mtk_init.h>
#include <mtgpio.h>
#include <platform_def.h>
/******************************************************************************
*Macro Definition
******************************************************************************/
#define GPIO_MODE_BITS 4
#define MAX_GPIO_MODE_PER_REG 8
#define MAX_GPIO_REG_BITS 32
#define DIR_BASE (GPIO_BASE + 0x000)
#define DOUT_BASE (GPIO_BASE + 0x100)
#define DIN_BASE (GPIO_BASE + 0x200)
#define MODE_BASE (GPIO_BASE + 0x300)
#define SET 0x4
#define CLR 0x8
static void mt_set_gpio_dir_chip(uint32_t pin, int dir)
{
uint32_t pos, bit;
assert(pin < MAX_GPIO_PIN);
assert(dir < MT_GPIO_DIR_MAX);
pos = pin / MAX_GPIO_REG_BITS;
bit = pin % MAX_GPIO_REG_BITS;
if (dir == MT_GPIO_DIR_IN) {
mmio_write_32(DIR_BASE + 0x10U * pos + CLR, 1U << bit);
} else {
mmio_write_32(DIR_BASE + 0x10U * pos + SET, 1U << bit);
}
}
static int mt_get_gpio_dir_chip(uint32_t pin)
{
uint32_t pos, bit;
uint32_t reg;
assert(pin < MAX_GPIO_PIN);
pos = pin / MAX_GPIO_REG_BITS;
bit = pin % MAX_GPIO_REG_BITS;
reg = mmio_read_32(DIR_BASE + 0x10U * pos);
return (((reg & (1U << bit)) != 0U) ? MT_GPIO_DIR_OUT : MT_GPIO_DIR_IN);
}
static void mt_set_gpio_out_chip(uint32_t pin, int output)
{
uint32_t pos, bit;
assert(pin < MAX_GPIO_PIN);
assert(output < MT_GPIO_OUT_MAX);
pos = pin / MAX_GPIO_REG_BITS;
bit = pin % MAX_GPIO_REG_BITS;
if (output == MT_GPIO_OUT_ZERO) {
mmio_write_32(DOUT_BASE + 0x10U * pos + CLR, 1U << bit);
} else {
mmio_write_32(DOUT_BASE + 0x10U * pos + SET, 1U << bit);
}
}
static int mt_get_gpio_in_chip(uint32_t pin)
{
uint32_t pos, bit;
uint32_t reg;
assert(pin < MAX_GPIO_PIN);
pos = pin / MAX_GPIO_REG_BITS;
bit = pin % MAX_GPIO_REG_BITS;
reg = mmio_read_32(DIN_BASE + 0x10U * pos);
return (((reg & (1U << bit)) != 0U) ? 1 : 0);
}
static void mt_gpio_set_spec_pull_pupd(uint32_t pin, int enable,
int select)
{
uintptr_t reg1;
uintptr_t reg2;
struct mt_pin_info gpio_info;
gpio_info = mt_pin_infos[pin];
uint32_t bit = gpio_info.bit;
reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
reg2 = reg1 + (gpio_info.base & 0xf0);
if (enable == MT_GPIO_PULL_ENABLE) {
mmio_write_32(reg2 + SET, (1U << bit));
if (select == MT_GPIO_PULL_DOWN) {
mmio_write_32(reg1 + SET, (1U << bit));
} else {
mmio_write_32(reg1 + CLR, (1U << bit));
}
} else {
mmio_write_32(reg2 + CLR, (1U << bit));
mmio_write_32((reg2 + 0x010U) + CLR, (1U << bit));
}
}
static void mt_gpio_set_pull_pu_pd(uint32_t pin, int enable,
int select)
{
uintptr_t reg1;
uintptr_t reg2;
struct mt_pin_info gpio_info;
gpio_info = mt_pin_infos[pin];
uint32_t bit = gpio_info.bit;
reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
reg2 = reg1 - (gpio_info.base & 0xf0);
if (enable == MT_GPIO_PULL_ENABLE) {
if (select == MT_GPIO_PULL_DOWN) {
mmio_write_32(reg1 + CLR, (1U << bit));
mmio_write_32(reg2 + SET, (1U << bit));
} else {
mmio_write_32(reg2 + CLR, (1U << bit));
mmio_write_32(reg1 + SET, (1U << bit));
}
} else {
mmio_write_32(reg1 + CLR, (1U << bit));
mmio_write_32(reg2 + CLR, (1U << bit));
}
}
static void mt_gpio_set_pull_chip(uint32_t pin, int enable,
int select)
{
struct mt_pin_info gpio_info;
gpio_info = mt_pin_infos[pin];
if (gpio_info.flag) {
mt_gpio_set_spec_pull_pupd(pin, enable, select);
} else {
mt_gpio_set_pull_pu_pd(pin, enable, select);
}
}
static int mt_gpio_get_spec_pull_pupd(uint32_t pin)
{
uintptr_t reg1;
uintptr_t reg2;
uint32_t r0;
uint32_t r1;
struct mt_pin_info gpio_info;
gpio_info = mt_pin_infos[pin];
uint32_t bit = gpio_info.bit;
reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
reg2 = reg1 + (gpio_info.base & 0xf0);
r0 = (mmio_read_32(reg2) >> bit) & 1U;
r1 = (mmio_read_32(reg2 + 0x010) >> bit) & 1U;
if (r0 == 0U && r1 == 0U) {
return MT_GPIO_PULL_NONE;
} else {
if (mmio_read_32(reg1) & (1U << bit)) {
return MT_GPIO_PULL_DOWN;
} else {
return MT_GPIO_PULL_UP;
}
}
}
static int mt_gpio_get_pull_pu_pd(uint32_t pin)
{
uintptr_t reg1;
uintptr_t reg2;
uint32_t pu;
uint32_t pd;
struct mt_pin_info gpio_info;
gpio_info = mt_pin_infos[pin];
uint32_t bit = gpio_info.bit;
reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
reg2 = reg1 - (gpio_info.base & 0xf0);
pu = (mmio_read_32(reg1) >> bit) & 1U;
pd = (mmio_read_32(reg2) >> bit) & 1U;
if (pu == 1U) {
return MT_GPIO_PULL_UP;
} else if (pd == 1U) {
return MT_GPIO_PULL_DOWN;
} else {
return MT_GPIO_PULL_NONE;
}
}
static int mt_gpio_get_pull_chip(uint32_t pin)
{
struct mt_pin_info gpio_info;
gpio_info = mt_pin_infos[pin];
if (gpio_info.flag) {
return mt_gpio_get_spec_pull_pupd(pin);
} else {
return mt_gpio_get_pull_pu_pd(pin);
}
}
static void mt_set_gpio_pull_select_chip(uint32_t pin, int sel)
{
assert(pin < MAX_GPIO_PIN);
if (sel == MT_GPIO_PULL_NONE) {
mt_gpio_set_pull_chip(pin, MT_GPIO_PULL_DISABLE, MT_GPIO_PULL_DOWN);
} else if (sel == MT_GPIO_PULL_UP) {
mt_gpio_set_pull_chip(pin, MT_GPIO_PULL_ENABLE, MT_GPIO_PULL_UP);
} else if (sel == MT_GPIO_PULL_DOWN) {
mt_gpio_set_pull_chip(pin, MT_GPIO_PULL_ENABLE, MT_GPIO_PULL_DOWN);
}
}
/* get pull-up or pull-down, regardless of resistor value */
static int mt_get_gpio_pull_select_chip(uint32_t pin)
{
assert(pin < MAX_GPIO_PIN);
return mt_gpio_get_pull_chip(pin);
}
static void mt_set_gpio_dir(int gpio, int direction)
{
mt_set_gpio_dir_chip((uint32_t)gpio, direction);
}
static int mt_get_gpio_dir(int gpio)
{
uint32_t pin;
pin = (uint32_t)gpio;
return mt_get_gpio_dir_chip(pin);
}
static void mt_set_gpio_pull(int gpio, int pull)
{
uint32_t pin;
pin = (uint32_t)gpio;
mt_set_gpio_pull_select_chip(pin, pull);
}
static int mt_get_gpio_pull(int gpio)
{
uint32_t pin;
pin = (uint32_t)gpio;
return mt_get_gpio_pull_select_chip(pin);
}
static void mt_set_gpio_out(int gpio, int value)
{
uint32_t pin;
pin = (uint32_t)gpio;
mt_set_gpio_out_chip(pin, value);
}
static int mt_get_gpio_in(int gpio)
{
uint32_t pin;
pin = (uint32_t)gpio;
return mt_get_gpio_in_chip(pin);
}
const gpio_ops_t mtgpio_ops = {
.get_direction = mt_get_gpio_dir,
.set_direction = mt_set_gpio_dir,
.get_value = mt_get_gpio_in,
.set_value = mt_set_gpio_out,
.set_pull = mt_set_gpio_pull,
.get_pull = mt_get_gpio_pull,
};
int mt_gpio_init(void)
{
gpio_init(&mtgpio_ops);
return 0;
}
MTK_PLAT_SETUP_0_INIT(mt_gpio_init);
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_GPIO_COMMON_H
#define MT_GPIO_COMMON_H
#include <stdbool.h>
#include <stdint.h>
#include <plat/common/common_def.h>
/* Error Code No. */
#define RSUCCESS 0
#define ERACCESS 1
#define ERINVAL 2
#define ERWRAPPER 3
#define MAX_GPIO_PIN MT_GPIO_BASE_MAX
/* GPIO MODE CONTROL VALUE*/
typedef enum {
GPIO_MODE_UNSUPPORTED = -1,
GPIO_MODE_GPIO = 0,
GPIO_MODE_00 = 0,
GPIO_MODE_01,
GPIO_MODE_02,
GPIO_MODE_03,
GPIO_MODE_04,
GPIO_MODE_05,
GPIO_MODE_06,
GPIO_MODE_07,
GPIO_MODE_MAX,
GPIO_MODE_DEFAULT = GPIO_MODE_00,
} GPIO_MODE;
/* GPIO DIRECTION */
typedef enum {
MT_GPIO_DIR_UNSUPPORTED = -1,
MT_GPIO_DIR_OUT = 0,
MT_GPIO_DIR_IN = 1,
MT_GPIO_DIR_MAX,
MT_GPIO_DIR_DEFAULT = MT_GPIO_DIR_IN,
} GPIO_DIR;
/* GPIO PULL ENABLE*/
typedef enum {
MT_GPIO_PULL_EN_UNSUPPORTED = -1,
MT_GPIO_PULL_DISABLE = 0,
MT_GPIO_PULL_ENABLE = 1,
MT_GPIO_PULL_ENABLE_R0 = 2,
MT_GPIO_PULL_ENABLE_R1 = 3,
MT_GPIO_PULL_ENABLE_R0R1 = 4,
MT_GPIO_PULL_EN_MAX,
MT_GPIO_PULL_EN_DEFAULT = MT_GPIO_PULL_ENABLE,
} GPIO_PULL_EN;
/* GPIO PULL-UP/PULL-DOWN*/
typedef enum {
MT_GPIO_PULL_UNSUPPORTED = -1,
MT_GPIO_PULL_NONE = 0,
MT_GPIO_PULL_UP = 1,
MT_GPIO_PULL_DOWN = 2,
MT_GPIO_PULL_MAX,
MT_GPIO_PULL_DEFAULT = MT_GPIO_PULL_DOWN
} GPIO_PULL;
/* GPIO OUTPUT */
typedef enum {
MT_GPIO_OUT_UNSUPPORTED = -1,
MT_GPIO_OUT_ZERO = 0,
MT_GPIO_OUT_ONE = 1,
MT_GPIO_OUT_MAX,
MT_GPIO_OUT_DEFAULT = MT_GPIO_OUT_ZERO,
MT_GPIO_DATA_OUT_DEFAULT = MT_GPIO_OUT_ZERO, /*compatible with DCT*/
} GPIO_OUT;
/* GPIO INPUT */
typedef enum {
MT_GPIO_IN_UNSUPPORTED = -1,
MT_GPIO_IN_ZERO = 0,
MT_GPIO_IN_ONE = 1,
MT_GPIO_IN_MAX,
} GPIO_IN;
#define PIN(_id, _flag, _bit, _base, _offset) { \
.id = _id, \
.flag = _flag, \
.bit = _bit, \
.base = _base, \
.offset = _offset, \
}
struct mt_pin_info {
uint8_t id;
uint8_t flag;
uint8_t bit;
uint16_t base;
uint16_t offset;
};
int mt_gpio_init(void);
uintptr_t mt_gpio_find_reg_addr(uint32_t pin);
#endif /* MT_GPIO_COMMON_H */
@@ -0,0 +1,18 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := gpio
LOCAL_SRCS-y := drivers/gpio/gpio.c
LOCAL_SRCS-y += ${LOCAL_DIR}/mtgpio_common.c
LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtgpio.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mtk_iommu_plat.h>
#include <mtk_mmap_pool.h>
#include <platform_def.h>
/* mm iommu */
#define SMI_L0_ID (0)
#define SMI_L1_ID (1)
#define SMI_L2_ID (2)
#define SMI_L3_ID (3)
#define SMI_L4_ID (4)
#define SMI_L5_ID (5)
#define SMI_L6_ID (6)
#define SMI_L7_ID (7)
#define SMI_L9_ID (8)
#define SMI_L10_ID (9)
#define SMI_L11A_ID (10)
#define SMI_L11B_ID (11)
#define SMI_L11C_ID (12)
#define SMI_L12_ID (13)
#define SMI_L13_ID (14)
#define SMI_L14_ID (15)
#define SMI_L15_ID (16)
#define SMI_L16A_ID (17)
#define SMI_L16B_ID (18)
#define SMI_L17A_ID (19)
#define SMI_L17B_ID (20)
#define SMI_L19_ID (21)
#define SMI_L21_ID (22)
#define SMI_L23_ID (23)
#define SMI_L27_ID (24)
#define SMI_L28_ID (25)
/* infra iommu */
#define PERI_MST_PROT (0x710)
#define PERICFG_AO_IOMMU_1 (0x714)
#define MMU_DEV_PCIE_0 (0)
#define IFR_CFG_GROUP_NUM (1)
static struct mtk_smi_larb_config mt8188_larb_cfg[SMI_LARB_NUM] = {
[SMI_L0_ID] = LARB_CFG_ENTRY(SMI_LARB_0_BASE, 7, 0),
[SMI_L1_ID] = LARB_CFG_ENTRY(SMI_LARB_1_BASE, 7, 0),
[SMI_L2_ID] = LARB_CFG_ENTRY(SMI_LARB_2_BASE, 5, 0),
[SMI_L3_ID] = LARB_CFG_ENTRY(SMI_LARB_3_BASE, 7, 0),
[SMI_L4_ID] = LARB_CFG_ENTRY(SMI_LARB_4_BASE, 7, 0),
[SMI_L5_ID] = LARB_CFG_ENTRY(SMI_LARB_5_BASE, 8, 0),
[SMI_L6_ID] = LARB_CFG_ENTRY(SMI_LARB_6_BASE, 4, 0),
[SMI_L7_ID] = LARB_CFG_ENTRY(SMI_LARB_7_BASE, 3, 0),
[SMI_L9_ID] = LARB_CFG_ENTRY(SMI_LARB_9_BASE, 25, 0),
[SMI_L10_ID] = LARB_CFG_ENTRY(SMI_LARB_10_BASE, 20, 0),
[SMI_L11A_ID] = LARB_CFG_ENTRY(SMI_LARB_11A_BASE, 30, 0),
[SMI_L11B_ID] = LARB_CFG_ENTRY(SMI_LARB_11B_BASE, 30, 0),
[SMI_L11C_ID] = LARB_CFG_ENTRY(SMI_LARB_11C_BASE, 30, 0),
[SMI_L12_ID] = LARB_CFG_ENTRY(SMI_LARB_12_BASE, 16, 0),
[SMI_L13_ID] = LARB_CFG_ENTRY(SMI_LARB_13_BASE, 24, 0),
[SMI_L14_ID] = LARB_CFG_ENTRY(SMI_LARB_14_BASE, 23, 0),
[SMI_L15_ID] = LARB_CFG_ENTRY(SMI_LARB_15_BASE, 19, 0),
[SMI_L16A_ID] = LARB_CFG_ENTRY(SMI_LARB_16A_BASE, 17, 0),
[SMI_L16B_ID] = LARB_CFG_ENTRY(SMI_LARB_16B_BASE, 17, 0),
[SMI_L17A_ID] = LARB_CFG_ENTRY(SMI_LARB_17A_BASE, 7, 0),
[SMI_L17B_ID] = LARB_CFG_ENTRY(SMI_LARB_17B_BASE, 7, 0),
/* venc nbm ports (5/6/11/15/16/17) to sram */
[SMI_L19_ID] = LARB_CFG_ENTRY_WITH_PATH(SMI_LARB_19_BASE, 27, 0, 0x38860),
[SMI_L21_ID] = LARB_CFG_ENTRY(SMI_LARB_21_BASE, 11, 0),
[SMI_L23_ID] = LARB_CFG_ENTRY(SMI_LARB_23_BASE, 9, 0),
[SMI_L27_ID] = LARB_CFG_ENTRY(SMI_LARB_27_BASE, 4, 0),
[SMI_L28_ID] = LARB_CFG_ENTRY(SMI_LARB_28_BASE, 0, 0),
};
static bool is_protected;
static uint32_t mt8188_ifr_mst_cfg_base[IFR_CFG_GROUP_NUM] = {
PERICFG_AO_BASE,
};
static uint32_t mt8188_ifr_mst_cfg_offs[IFR_CFG_GROUP_NUM] = {
PERICFG_AO_IOMMU_1,
};
static struct mtk_ifr_mst_config mt8188_ifr_mst_cfg[MMU_DEV_NUM] = {
[MMU_DEV_PCIE_0] = IFR_MST_CFG_ENTRY(0, 18),
};
struct mtk_smi_larb_config *g_larb_cfg = &mt8188_larb_cfg[0];
struct mtk_ifr_mst_config *g_ifr_mst_cfg = &mt8188_ifr_mst_cfg[0];
uint32_t *g_ifr_mst_cfg_base = &mt8188_ifr_mst_cfg_base[0];
uint32_t *g_ifr_mst_cfg_offs = &mt8188_ifr_mst_cfg_offs[0];
/* Protect infra iommu enable setting registers as secure access. */
void mtk_infra_iommu_enable_protect(void)
{
if (!is_protected) {
mmio_write_32(PERICFG_AO_BASE + PERI_MST_PROT, 0xffffffff);
is_protected = true;
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IOMMU_PLAT_H
#define IOMMU_PLAT_H
#include <mtk_iommu_priv.h>
/* mm iommu */
#define SMI_LARB_NUM (26)
extern struct mtk_smi_larb_config *g_larb_cfg;
/* infra iommu */
#define MMU_DEV_NUM (1)
extern struct mtk_ifr_mst_config *g_ifr_mst_cfg;
extern uint32_t *g_ifr_mst_cfg_base;
extern uint32_t *g_ifr_mst_cfg_offs;
extern void mtk_infra_iommu_enable_protect(void);
#endif /* IOMMU_PLAT_H */
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IOMMU_PRIV_H
#define IOMMU_PRIV_H
#include <common/debug.h>
#include <lib/mmio.h>
#include <mtk_sip_svc.h>
#define LARB_CFG_ENTRY(bs, p_nr, dom) \
{ .base = (bs), .port_nr = (p_nr), \
.dom_id = (dom), .to_sram = 0, }
#define LARB_CFG_ENTRY_WITH_PATH(bs, p_nr, dom, sram) \
{ .base = (bs), .port_nr = (p_nr), \
.dom_id = (dom), .to_sram = (sram), }
#define IFR_MST_CFG_ENTRY(idx, bit) \
{ .cfg_addr_idx = (idx), .r_mmu_en_bit = (bit), }
enum IOMMU_ATF_CMD {
IOMMU_ATF_CMD_CONFIG_SMI_LARB, /* For mm master to enable iommu */
IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU, /* For infra master to enable iommu */
IOMMU_ATF_CMD_COUNT,
};
struct mtk_smi_larb_config {
uint32_t base;
uint32_t port_nr;
uint32_t dom_id;
uint32_t to_sram;
uint32_t sec_en_msk;
};
struct mtk_ifr_mst_config {
uint8_t cfg_addr_idx;
uint8_t r_mmu_en_bit;
};
#endif /* IOMMU_PRIV_H */
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <mtk_iommu_plat.h>
/* defination */
/* smi larb */
#define SMI_LARB_NON_SEC_CON(port) (0x380 + ((port) << 2))
#define PATH_SEL_MASK (0xf0000) /* to sram (INT) */
#define SMI_LARB_SEC_CON_INT(port) (0xf00 + ((port) << 2))
#define SMI_LARB_SEC_CON(port) (0xf80 + ((port) << 2))
#define MMU_MASK BIT(0)
#define MMU_EN(en) ((!!(en)) << 0)
#define SEC_MASK BIT(1)
#define SEC_EN(en) ((!!(en)) << 1)
#define DOMAIN_MASK (0x1f << 4)
#define SMI_MMU_EN(port) (0x1 << (port))
/* infra master */
#define IFR_CFG_MMU_EN_MSK(r_bit) (0x3 << (r_bit))
/* smi larb configure */
/*
* If multimedia security config is enabled, the SMI config register must be
* configurated in security world.
* And the SRAM path is also configurated here to enhance security.
*/
static void mtk_smi_larb_port_config_to_sram(
const struct mtk_smi_larb_config *larb,
uint32_t port_id)
{
mmio_clrbits_32(larb->base + SMI_LARB_SEC_CON_INT(port_id),
MMU_MASK | SEC_MASK | DOMAIN_MASK);
mmio_setbits_32(larb->base + SMI_LARB_NON_SEC_CON(port_id),
PATH_SEL_MASK);
}
static void mtk_smi_port_config(const struct mtk_smi_larb_config *larb,
uint32_t port_id, uint8_t mmu_en, uint8_t sec_en)
{
mmio_clrsetbits_32(larb->base + SMI_LARB_SEC_CON(port_id),
MMU_MASK | SEC_MASK | DOMAIN_MASK,
MMU_EN(mmu_en) | SEC_EN(sec_en));
}
static int mtk_smi_larb_port_config_sec(uint32_t larb_id, uint32_t mmu_en_msk)
{
uint32_t port_id, port_nr;
const struct mtk_smi_larb_config *larb;
uint32_t to_sram;
uint8_t mmu_en;
if (larb_id >= SMI_LARB_NUM) {
return MTK_SIP_E_INVALID_PARAM;
}
larb = &g_larb_cfg[larb_id];
port_nr = larb->port_nr;
to_sram = larb->to_sram;
for (port_id = 0; port_id < port_nr; port_id++) {
if ((to_sram & BIT(port_id)) > 0U) {
mtk_smi_larb_port_config_to_sram(larb, port_id);
continue;
}
mmu_en = !!(mmu_en_msk & SMI_MMU_EN(port_id));
mtk_smi_port_config(larb, port_id, mmu_en, 0);
}
return MTK_SIP_E_SUCCESS;
}
static int mtk_infra_master_config_sec(uint32_t dev_id, uint32_t enable)
{
const struct mtk_ifr_mst_config *ifr_cfg;
uint32_t reg_addr;
mtk_infra_iommu_enable_protect();
if (dev_id >= MMU_DEV_NUM) {
return MTK_SIP_E_NOT_SUPPORTED;
}
ifr_cfg = &g_ifr_mst_cfg[dev_id];
reg_addr = g_ifr_mst_cfg_base[(ifr_cfg->cfg_addr_idx)] +
g_ifr_mst_cfg_offs[(ifr_cfg->cfg_addr_idx)];
if (enable > 0U) {
mmio_setbits_32(reg_addr, IFR_CFG_MMU_EN_MSK(ifr_cfg->r_mmu_en_bit));
} else {
mmio_clrbits_32(reg_addr, IFR_CFG_MMU_EN_MSK(ifr_cfg->r_mmu_en_bit));
}
return MTK_SIP_E_SUCCESS;
}
static u_register_t mtk_iommu_handler(u_register_t x1, u_register_t x2,
u_register_t x3, u_register_t x4,
void *handle, struct smccc_res *smccc_ret)
{
uint32_t cmd_id = x1, mdl_id = x2, val = x3;
int ret = MTK_SIP_E_NOT_SUPPORTED;
(void)x4;
(void)handle;
switch (cmd_id) {
case IOMMU_ATF_CMD_CONFIG_SMI_LARB:
ret = mtk_smi_larb_port_config_sec(mdl_id, val);
break;
case IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU:
ret = mtk_infra_master_config_sec(mdl_id, val);
break;
default:
break;
}
return ret;
}
DECLARE_SMC_HANDLER(MTK_SIP_IOMMU_CONTROL, mtk_iommu_handler);
@@ -0,0 +1,17 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mtk_iommu
LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_iommu_smc.c
LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtk_iommu_plat.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <mtk_mmap_pool.h>
#include <platform_def.h>
static const mmap_region_t mcusys_mmap[] MTK_MMAP_SECTION = {
MAP_REGION_FLAT(MCUCFG_BASE, MCUCFG_REG_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
{0}
};
DECLARE_MTK_MMAP_REGIONS(mcusys_mmap);
@@ -0,0 +1,15 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mcusys
PLAT_INCLUDES += -I$(LOCAL_DIR)/$(MCUSYS_VERSION)
LOCAL_SRCS-y := $(LOCAL_DIR)/mcusys.c
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,232 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MCUCFG_V1_H
#define MCUCFG_V1_H
#ifndef __ASSEMBLER__
#include <stdint.h>
#endif /*__ASSEMBLER__*/
#include <platform_def.h>
#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_BASE + 0x2290 + ((cpu) * 8))
#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_BASE + 0x2294 + ((cpu) * 8))
#define MP2_CPUCFG (MCUCFG_BASE + 0x2208)
#define MP0_CPUTOP_SPMC_CTL (MCUCFG_BASE + 0x788)
#define MP1_CPUTOP_SPMC_CTL (MCUCFG_BASE + 0x78C)
#define MP1_CPUTOP_SPMC_SRAM_CTL (MCUCFG_BASE + 0x790)
#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) (MCUCFG_BASE + 0x1C30 + \
(cluster) * 0x2000 + (cpu) * 4)
#define CPUSYS0_CPU0_SPMC_CTL (MCUCFG_BASE + 0x1C30)
#define CPUSYS0_CPU1_SPMC_CTL (MCUCFG_BASE + 0x1C34)
#define CPUSYS0_CPU2_SPMC_CTL (MCUCFG_BASE + 0x1C38)
#define CPUSYS0_CPU3_SPMC_CTL (MCUCFG_BASE + 0x1C3C)
#define CPUSYS1_CPU0_SPMC_CTL (MCUCFG_BASE + 0x3C30)
#define CPUSYS1_CPU1_SPMC_CTL (MCUCFG_BASE + 0x3C34)
#define CPUSYS1_CPU2_SPMC_CTL (MCUCFG_BASE + 0x3C38)
#define CPUSYS1_CPU3_SPMC_CTL (MCUCFG_BASE + 0x3C3C)
/* CPC related registers */
#define CPC_MCUSYS_CPC_OFF_THRES (MCUCFG_BASE + 0xA714)
#define CPC_MCUSYS_PWR_CTRL (MCUCFG_BASE + 0xA804)
#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG (MCUCFG_BASE + 0xA814)
#define CPC_MCUSYS_LAST_CORE_REQ (MCUCFG_BASE + 0xA818)
#define CPC_MCUSYS_MP_LAST_CORE_RESP (MCUCFG_BASE + 0xA81C)
#define CPC_MCUSYS_LAST_CORE_RESP (MCUCFG_BASE + 0xA824)
#define CPC_MCUSYS_PWR_ON_MASK (MCUCFG_BASE + 0xA828)
#define CPC_SPMC_PWR_STATUS (MCUCFG_BASE + 0xA840)
#define CPC_MCUSYS_CPU_ON_SW_HINT_SET (MCUCFG_BASE + 0xA8A8)
#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR (MCUCFG_BASE + 0xA8AC)
#define CPC_MCUSYS_CPC_DBG_SETTING (MCUCFG_BASE + 0xAB00)
#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE (MCUCFG_BASE + 0xAB04)
#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE (MCUCFG_BASE + 0xAB08)
#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE (MCUCFG_BASE + 0xAB0C)
#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE (MCUCFG_BASE + 0xAB10)
#define CPC_MCUSYS_TRACE_SEL (MCUCFG_BASE + 0xAB14)
#define CPC_MCUSYS_TRACE_DATA (MCUCFG_BASE + 0xAB20)
#define CPC_MCUSYS_CLUSTER_COUNTER (MCUCFG_BASE + 0xAB70)
#define CPC_MCUSYS_CLUSTER_COUNTER_CLR (MCUCFG_BASE + 0xAB74)
/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG bit control */
#define CPC_CTRL_ENABLE BIT(16)
#define SSPM_CORE_PWR_ON_EN BIT(7) /* for cpu-hotplug */
#define SSPM_ALL_PWR_CTRL_EN BIT(13) /* for cpu-hotplug */
#define GIC_WAKEUP_IGNORE(cpu) BIT(21 + cpu)
#define CPC_MCUSYS_CPC_RESET_ON_KEEP_ON BIT(17)
#define CPC_MCUSYS_CPC_RESET_PWR_ON_EN BIT(20)
/* SPMC related registers */
#define SPM_MCUSYS_PWR_CON (MCUCFG_BASE + 0xD200)
#define SPM_MP0_CPUTOP_PWR_CON (MCUCFG_BASE + 0xD204)
#define SPM_MP0_CPU0_PWR_CON (MCUCFG_BASE + 0xD208)
#define SPM_MP0_CPU1_PWR_CON (MCUCFG_BASE + 0xD20C)
#define SPM_MP0_CPU2_PWR_CON (MCUCFG_BASE + 0xD210)
#define SPM_MP0_CPU3_PWR_CON (MCUCFG_BASE + 0xD214)
#define SPM_MP0_CPU4_PWR_CON (MCUCFG_BASE + 0xD218)
#define SPM_MP0_CPU5_PWR_CON (MCUCFG_BASE + 0xD21C)
#define SPM_MP0_CPU6_PWR_CON (MCUCFG_BASE + 0xD220)
#define SPM_MP0_CPU7_PWR_CON (MCUCFG_BASE + 0xD224)
/* bit fields of SPM_*_PWR_CON */
#define PWR_ON_ACK BIT(31)
#define VPROC_EXT_OFF BIT(7)
#define DORMANT_EN BIT(6)
#define RESETPWRON_CONFIG BIT(5)
#define PWR_CLK_DIS BIT(4)
#define PWR_ON BIT(2)
#define PWR_RST_B BIT(0)
#define SPARK2LDO (MCUCFG_BASE + 0x2700)
/* APB Module mcucfg */
#define MP0_CA7_CACHE_CONFIG (MCUCFG_BASE + 0x000)
#define MP0_AXI_CONFIG (MCUCFG_BASE + 0x02C)
#define MP0_MISC_CONFIG0 (MCUCFG_BASE + 0x030)
#define MP0_MISC_CONFIG1 (MCUCFG_BASE + 0x034)
#define MP0_MISC_CONFIG2 (MCUCFG_BASE + 0x038)
#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MCUCFG_BASE + 0x038 + ((cpu) * 8))
#define MP0_MISC_CONFIG3 (MCUCFG_BASE + 0x03C)
#define MP0_MISC_CONFIG9 (MCUCFG_BASE + 0x054)
#define MP0_CA7_MISC_CONFIG (MCUCFG_BASE + 0x064)
#define MP0_RW_RSVD0 (MCUCFG_BASE + 0x06C)
#define MP1_CA7_CACHE_CONFIG (MCUCFG_BASE + 0x200)
#define MP1_AXI_CONFIG (MCUCFG_BASE + 0x22C)
#define MP1_MISC_CONFIG0 (MCUCFG_BASE + 0x230)
#define MP1_MISC_CONFIG1 (MCUCFG_BASE + 0x234)
#define MP1_MISC_CONFIG2 (MCUCFG_BASE + 0x238)
#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MCUCFG_BASE + 0x238 + ((cpu) * 8))
#define MP1_MISC_CONFIG3 (MCUCFG_BASE + 0x23C)
#define MP1_MISC_CONFIG9 (MCUCFG_BASE + 0x254)
#define MP1_CA7_MISC_CONFIG (MCUCFG_BASE + 0x264)
#define CCI_ADB400_DCM_CONFIG (MCUCFG_BASE + 0x740)
#define SYNC_DCM_CONFIG (MCUCFG_BASE + 0x744)
#define MP0_CLUSTER_CFG0 (MCUCFG_BASE + 0xC8D0)
#define MP0_SPMC (MCUCFG_BASE + 0x788)
#define MP1_SPMC (MCUCFG_BASE + 0x78C)
#define MP2_AXI_CONFIG (MCUCFG_BASE + 0x220C)
#define MP2_AXI_CONFIG_ACINACTM BIT(0)
#define MP2_AXI_CONFIG_AINACTS BIT(4)
#define MPx_AXI_CONFIG_ACINACTM BIT(4)
#define MPx_AXI_CONFIG_AINACTS BIT(5)
#define MPx_CA7_MISC_CONFIG_standbywfil2 BIT(28)
#define MP0_CPU0_STANDBYWFE BIT(20)
#define MP0_CPU1_STANDBYWFE BIT(21)
#define MP0_CPU2_STANDBYWFE BIT(22)
#define MP0_CPU3_STANDBYWFE BIT(23)
#define MP1_CPU0_STANDBYWFE BIT(20)
#define MP1_CPU1_STANDBYWFE BIT(21)
#define MP1_CPU2_STANDBYWFE BIT(22)
#define MP1_CPU3_STANDBYWFE BIT(23)
#define CPUSYS0_SPARKVRETCNTRL (MCUCFG_BASE+0x1c00)
#define CPUSYS0_SPARKEN (MCUCFG_BASE+0x1c04)
#define CPUSYS0_AMUXSEL (MCUCFG_BASE+0x1c08)
#define CPUSYS1_SPARKVRETCNTRL (MCUCFG_BASE+0x3c00)
#define CPUSYS1_SPARKEN (MCUCFG_BASE+0x3c04)
#define CPUSYS1_AMUXSEL (MCUCFG_BASE+0x3c08)
#define MP2_PWR_RST_CTL (MCUCFG_BASE + 0x2008)
#define MP2_PTP3_CPUTOP_SPMC0 (MCUCFG_BASE + 0x22A0)
#define MP2_PTP3_CPUTOP_SPMC1 (MCUCFG_BASE + 0x22A4)
#define MP2_COQ (MCUCFG_BASE + 0x22BC)
#define MP2_COQ_SW_DIS BIT(0)
#define MP2_CA15M_MON_SEL (MCUCFG_BASE + 0x2400)
#define MP2_CA15M_MON_L (MCUCFG_BASE + 0x2404)
#define CPUSYS2_CPU0_SPMC_CTL (MCUCFG_BASE + 0x2430)
#define CPUSYS2_CPU1_SPMC_CTL (MCUCFG_BASE + 0x2438)
#define CPUSYS2_CPU0_SPMC_STA (MCUCFG_BASE + 0x2434)
#define CPUSYS2_CPU1_SPMC_STA (MCUCFG_BASE + 0x243C)
#define MP0_CA7L_DBG_PWR_CTRL (MCUCFG_BASE + 0x068)
#define MP1_CA7L_DBG_PWR_CTRL (MCUCFG_BASE + 0x268)
#define BIG_DBG_PWR_CTRL (MCUCFG_BASE + 0x75C)
#define MP2_SW_RST_B BIT(0)
#define MP2_TOPAON_APB_MASK BIT(1)
#define B_SW_HOT_PLUG_RESET BIT(30)
#define B_SW_PD_OFFSET (18)
#define B_SW_PD (0x3F << B_SW_PD_OFFSET)
#define B_SW_SRAM_SLEEPB_OFFSET (12)
#define B_SW_SRAM_SLEEPB (0x3F << B_SW_SRAM_SLEEPB_OFFSET)
#define B_SW_SRAM_ISOINTB BIT(9)
#define B_SW_ISO BIT(8)
#define B_SW_LOGIC_PDB BIT(7)
#define B_SW_LOGIC_PRE2_PDB BIT(6)
#define B_SW_LOGIC_PRE1_PDB BIT(5)
#define B_SW_FSM_OVERRIDE BIT(4)
#define B_SW_PWR_ON BIT(3)
#define B_SW_PWR_ON_OVERRIDE_EN BIT(2)
#define B_FSM_STATE_OUT_OFFSET (6)
#define B_FSM_STATE_OUT_MASK (0x1F << B_FSM_STATE_OUT_OFFSET)
#define B_SW_LOGIC_PDBO_ALL_OFF_ACK BIT(5)
#define B_SW_LOGIC_PDBO_ALL_ON_ACK BIT(4)
#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK BIT(3)
#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK BIT(2)
#define B_FSM_OFF (0U << B_FSM_STATE_OUT_OFFSET)
#define B_FSM_ON (1U << B_FSM_STATE_OUT_OFFSET)
#define B_FSM_RET (2U << B_FSM_STATE_OUT_OFFSET)
#ifndef __ASSEMBLER__
/* cpu boot mode */
enum mp0_coucfg_64bit_ctrl {
MP0_CPUCFG_64BIT_SHIFT = 12,
MP1_CPUCFG_64BIT_SHIFT = 28,
MP0_CPUCFG_64BIT = 0xfu << MP0_CPUCFG_64BIT_SHIFT,
MP1_CPUCFG_64BIT = 0xfu << MP1_CPUCFG_64BIT_SHIFT,
};
enum mp1_dis_rgu0_ctrl {
MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0,
MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4,
MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8,
MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12,
MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16,
MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT,
};
enum mp1_ainacts_ctrl {
MP1_AINACTS_SHIFT = 4,
MP1_AINACTS = 1U << MP1_AINACTS_SHIFT,
};
enum mp1_sw_cg_gen {
MP1_SW_CG_GEN_SHIFT = 12,
MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT,
};
enum mp1_l2rstdisable {
MP1_L2RSTDISABLE_SHIFT = 14,
MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT,
};
#endif /*__ASSEMBLER__*/
#endif /* MCUCFG_V1_H */
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_MSDC_PRIV_H
#define MT_MSDC_PRIV_H
#define MSDC_CQHCI_CFG 0x808
#define MSDC_CQHCI_CRYPTO_ENABLE BIT(1)
#endif
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <mt_msdc.h>
#include <platform_def.h>
uint64_t msdc_smc_dispatcher(uint64_t arg0, uint64_t arg1,
uint64_t arg2, uint64_t arg3)
{
INFO("[%s] msdc setup call from kernel\n", __func__);
mmio_setbits_32(MSDC0_BASE + MSDC_CQHCI_CFG, MSDC_CQHCI_CRYPTO_ENABLE);
return 0L;
}
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_MSDC_H
#define MT_MSDC_H
#include <mt_msdc_priv.h>
uint64_t msdc_smc_dispatcher(uint64_t arg0, uint64_t arg1,
uint64_t arg2, uint64_t arg3);
#endif
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <pmic.h>
#include <pmic_wrap_init.h>
void pmic_power_off(void)
{
pwrap_write(PMIC_PWRHOLD, 0x0);
}
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMIC_H
#define PMIC_H
#define PMIC_PWRHOLD (0xa08)
/* external API */
void pmic_power_off(void);
#endif /* PMIC_H */
@@ -0,0 +1,15 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := pmic
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic.c
PLAT_INCLUDES += -I${LOCAL_DIR}/
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMIC_WRAP_INIT_H
#define PMIC_WRAP_INIT_H
#include <stdint.h>
#include "platform_def.h"
#include <pmic_wrap_init_common.h>
static struct mt8188_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE;
/* PMIC_WRAP registers */
struct mt8188_pmic_wrap_regs {
uint32_t init_done;
uint32_t reserved[543];
uint32_t wacs2_cmd;
uint32_t wacs2_wdata;
uint32_t reserved1[3];
uint32_t wacs2_rdata;
uint32_t reserved2[3];
uint32_t wacs2_vldclr;
uint32_t wacs2_sta;
};
#endif /* PMIC_WRAP_INIT_H */
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2019-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <platform_def.h>
#include <pmic_wrap_init.h>
/* pmic wrap module wait_idle and read polling interval (in microseconds) */
enum {
WAIT_IDLE_POLLING_DELAY_US = 1,
READ_POLLING_DELAY_US = 2
};
static inline uint32_t wait_for_state_idle(uint32_t timeout_us,
void *wacs_register,
void *wacs_vldclr_register,
uint32_t *read_reg)
{
uint32_t reg_rdata;
uint32_t retry;
retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
WAIT_IDLE_POLLING_DELAY_US;
do {
udelay(WAIT_IDLE_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
/* if last read command timeout,clear vldclr bit
* read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
* write:FSM_REQ-->idle
*/
switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) &
RDATA_WACS_FSM_MASK)) {
case WACS_FSM_WFVLDCLR:
mmio_write_32((uintptr_t)wacs_vldclr_register, 1);
ERROR("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n");
break;
case WACS_FSM_WFDLE:
ERROR("WACS_FSM = WACS_FSM_WFDLE\n");
break;
case WACS_FSM_REQ:
ERROR("WACS_FSM = WACS_FSM_REQ\n");
break;
case WACS_FSM_IDLE:
goto done;
default:
break;
}
retry--;
} while (retry);
done:
if (!retry) /* timeout */
return E_PWR_WAIT_IDLE_TIMEOUT;
if (read_reg)
*read_reg = reg_rdata;
return 0;
}
static inline uint32_t wait_for_state_ready(uint32_t timeout_us,
void *wacs_register,
uint32_t *read_reg)
{
uint32_t reg_rdata;
uint32_t retry;
retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
do {
udelay(READ_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
if (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK)
== WACS_FSM_WFVLDCLR)
break;
retry--;
} while (retry);
if (!retry) { /* timeout */
ERROR("timeout when waiting for idle\n");
return E_PWR_WAIT_IDLE_TIMEOUT_READ;
}
if (read_reg)
*read_reg = reg_rdata;
return 0;
}
static int32_t pwrap_wacs2(uint32_t write,
uint32_t adr,
uint32_t wdata,
uint32_t *rdata,
uint32_t init_check)
{
uint32_t reg_rdata = 0;
uint32_t wacs_write = 0;
uint32_t wacs_adr = 0;
uint32_t wacs_cmd = 0;
uint32_t return_value = 0;
if (init_check) {
reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
/* Prevent someone to used pwrap before pwrap init */
if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
ERROR("initialization isn't finished\n");
return E_PWR_NOT_INIT_DONE;
}
}
reg_rdata = 0;
/* Check IDLE in advance */
return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE,
&mtk_pwrap->wacs2_rdata,
&mtk_pwrap->wacs2_vldclr,
0);
if (return_value != 0) {
ERROR("wait_for_fsm_idle fail,return_value=%d\n", return_value);
goto FAIL;
}
wacs_write = write << 31;
wacs_adr = (adr >> 1) << 16;
wacs_cmd = wacs_write | wacs_adr | wdata;
mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, wacs_cmd);
if (write == 0) {
if (rdata == NULL) {
ERROR("rdata is a NULL pointer\n");
return_value = E_PWR_INVALID_ARG;
goto FAIL;
}
return_value = wait_for_state_ready(TIMEOUT_READ,
&mtk_pwrap->wacs2_rdata,
&reg_rdata);
if (return_value != 0) {
ERROR("wait_for_fsm_vldclr fail,return_value=%d\n",
return_value);
goto FAIL;
}
*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
& RDATA_WACS_RDATA_MASK);
mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 1);
}
FAIL:
return return_value;
}
/* external API for pmic_wrap user */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
{
return pwrap_wacs2(0, adr, 0, rdata, 1);
}
int32_t pwrap_write(uint32_t adr, uint32_t wdata)
{
return pwrap_wacs2(1, adr, wdata, 0, 1);
}
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMIC_WRAP_INIT_COMMON_H
#define PMIC_WRAP_INIT_COMMON_H
#include <stdint.h>
#include "platform_def.h"
/* external API */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata);
int32_t pwrap_write(uint32_t adr, uint32_t wdata);
#define GET_WACS_FSM(x) ((x >> 1) & 0x7)
/* macro for SWINF_FSM */
#define SWINF_FSM_IDLE (0x00)
#define SWINF_FSM_REQ (0x02)
#define SWINF_FSM_WFDLE (0x04)
#define SWINF_FSM_WFVLDCLR (0x06)
#define SWINF_INIT_DONE (0x01)
/* timeout setting */
#define PWRAP_READ_US (1000)
#define PWRAP_WAIT_IDLE_US (1000)
/* error information flag */
enum pwrap_errno {
E_PWR_INVALID_ARG = 1,
E_PWR_INVALID_RW = 2,
E_PWR_INVALID_ADDR = 3,
E_PWR_INVALID_WDAT = 4,
E_PWR_INVALID_OP_MANUAL = 5,
E_PWR_NOT_IDLE_STATE = 6,
E_PWR_NOT_INIT_DONE = 7,
E_PWR_NOT_INIT_DONE_READ = 8,
E_PWR_WAIT_IDLE_TIMEOUT = 9,
E_PWR_WAIT_IDLE_TIMEOUT_READ = 10,
E_PWR_INIT_SIDLY_FAIL = 11,
E_PWR_RESET_TIMEOUT = 12,
E_PWR_TIMEOUT = 13,
E_PWR_INIT_RESET_SPI = 20,
E_PWR_INIT_SIDLY = 21,
E_PWR_INIT_REG_CLOCK = 22,
E_PWR_INIT_ENABLE_PMIC = 23,
E_PWR_INIT_DIO = 24,
E_PWR_INIT_CIPHER = 25,
E_PWR_INIT_WRITE_TEST = 26,
E_PWR_INIT_ENABLE_CRC = 27,
E_PWR_INIT_ENABLE_DEWRAP = 28,
E_PWR_INIT_ENABLE_EVENT = 29,
E_PWR_READ_TEST_FAIL = 30,
E_PWR_WRITE_TEST_FAIL = 31,
E_PWR_SWITCH_DIO = 32,
};
#endif /* PMIC_WRAP_INIT_COMMON_H */
@@ -0,0 +1,143 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include "platform_def.h"
#include "pmic_wrap_init.h"
/* pmic wrap module wait_idle and read polling interval (in microseconds) */
enum pwrap_polling_interval {
WAIT_IDLE_POLLING_DELAY_US = 1,
READ_POLLING_DELAY_US = 2
};
static uint32_t pwrap_check_idle(void *wacs_register, uint32_t timeout_us)
{
uint32_t reg_rdata = 0U, retry;
retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
WAIT_IDLE_POLLING_DELAY_US;
while (retry != 0) {
udelay(WAIT_IDLE_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
/* if last read command timeout,clear vldclr bit
* read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
* write:FSM_REQ-->idle
*/
switch (GET_WACS_FSM(reg_rdata)) {
case SWINF_FSM_WFVLDCLR:
mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
INFO("WACS_FSM = SWINF_FSM_WFVLDCLR\n");
break;
case SWINF_FSM_WFDLE:
INFO("WACS_FSM = SWINF_FSM_WFDLE\n");
break;
case SWINF_FSM_REQ:
INFO("WACS_FSM = SWINF_FSM_REQ\n");
break;
case SWINF_FSM_IDLE:
goto done;
default:
break;
}
retry--;
};
done:
if (retry == 0) {
/* timeout */
return E_PWR_WAIT_IDLE_TIMEOUT;
}
return 0U;
}
static uint32_t pwrap_check_vldclr(void *wacs_register, uint32_t timeout_us)
{
uint32_t reg_rdata = 0U, retry;
retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
while (retry != 0) {
udelay(READ_POLLING_DELAY_US);
reg_rdata = mmio_read_32((uintptr_t)wacs_register);
if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_WFVLDCLR) {
break;
}
retry--;
};
if (retry == 0) {
/* timeout */
return E_PWR_WAIT_IDLE_TIMEOUT;
}
return 0U;
}
static int32_t pwrap_wacs2(uint32_t write, uint32_t adr, uint32_t wdata,
uint32_t *rdata, uint32_t init_check)
{
uint32_t reg_rdata, return_value;
if (init_check != 0) {
if ((mmio_read_32((uintptr_t)&mtk_pwrap->init_done) & 0x1) == 0) {
ERROR("initialization isn't finished\n");
return E_PWR_NOT_INIT_DONE;
}
}
/* Wait for Software Interface FSM state to be IDLE. */
return_value = pwrap_check_idle(&mtk_pwrap->wacs2_sta,
PWRAP_WAIT_IDLE_US);
if (return_value != 0) {
return return_value;
}
/* Set the write data */
if (write == 1) {
/* Set the write data. */
mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_wdata, wdata);
}
/* Send the command. */
mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, (write << 29) | adr);
if (write == 0) {
/*
* Wait for Software Interface FSM state to be WFVLDCLR,
* read the data and clear the valid flag.
*/
return_value = pwrap_check_vldclr(&mtk_pwrap->wacs2_sta,
PWRAP_READ_US);
if (return_value != 0) {
return return_value;
}
if (rdata == NULL) {
return E_PWR_INVALID_ARG;
}
reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
*rdata = reg_rdata;
mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
}
return return_value;
}
/* external API for pmic_wrap user */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
{
return pwrap_wacs2(0, adr, 0, rdata, 1);
}
int32_t pwrap_write(uint32_t adr, uint32_t wdata)
{
return pwrap_wacs2(1, adr, wdata, 0, 1);
}
@@ -0,0 +1,20 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := pmic_wrap
ifeq (${USE_PMIC_WRAP_INIT_V2}, 1)
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_wrap_init_v2.c
else
LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_wrap_init.c
endif
PLAT_INCLUDES += -I${LOCAL_DIR}/
PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PTP3_PLAT_H
#define PTP3_PLAT_H
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <ptp3_common.h>
/* CPU Info */
#define NR_PTP3_CFG_CPU U(8)
#define PTP3_CFG_CPU_START_ID_L U(0)
#define PTP3_CFG_CPU_START_ID_B U(6)
#define PTP3_CFG_CPU_END_ID U(7)
#define NR_PTP3_CFG1_DATA U(2)
#define PTP3_CFG1_MASK (0x3000)
#define NR_PTP3_CFG2_DATA U(5)
#define PTP3_CFG3_MASK1 (0x1180)
#define PTP3_CFG3_MASK2 (0x35C0)
#define PTP3_CFG3_MASK3 (0x3DC0)
/* Central control */
static unsigned int ptp3_cfg1[NR_PTP3_CFG1_DATA][NR_PTP3_CFG] = {
{0x0C53A2A0, 0x1000},
{0x0C53A2A4, 0x1000}
};
static unsigned int ptp3_cfg2[NR_PTP3_CFG2_DATA][NR_PTP3_CFG] = {
{0x0C530404, 0x3A1000},
{0x0C530428, 0x13E0408},
{0x0C530434, 0xB22800},
{0x0C53043C, 0x750},
{0x0C530440, 0x0222c4cc}
};
static unsigned int ptp3_cfg3[NR_PTP3_CFG] = {0x0C530400, 0xC00};
static unsigned int ptp3_cfg3_ext[NR_PTP3_CFG] = {0x0C530400, 0xC00};
#endif /* PTP3_PLAT_H */
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#if MTK_PUBEVENT_ENABLE
#include <lib/pm/mtk_pm.h>
#endif
#include <ptp3_plat.h>
#define PTP3_CORE_OFT(core) (0x800 * (core))
static void ptp3_init(unsigned int core)
{
unsigned int i, addr, value;
if (core < PTP3_CFG_CPU_START_ID_B) {
mmio_clrsetbits_32(ptp3_cfg1[0][PTP3_CFG_ADDR], PTP3_CFG1_MASK,
ptp3_cfg1[0][PTP3_CFG_VALUE]);
} else {
mmio_clrsetbits_32(ptp3_cfg1[1][PTP3_CFG_ADDR], PTP3_CFG1_MASK,
ptp3_cfg1[1][PTP3_CFG_VALUE]);
}
if (core < PTP3_CFG_CPU_START_ID_B) {
for (i = 0; i < NR_PTP3_CFG2_DATA; i++) {
addr = ptp3_cfg2[i][PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
value = ptp3_cfg2[i][PTP3_CFG_VALUE];
mmio_write_32(addr, value);
}
} else {
for (i = 0; i < NR_PTP3_CFG2_DATA; i++) {
addr = ptp3_cfg2[i][PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
if (i == 2) {
value = ptp3_cfg2[i][PTP3_CFG_VALUE] + 0x5E0;
} else {
value = ptp3_cfg2[i][PTP3_CFG_VALUE];
}
mmio_write_32(addr, value);
}
}
if (core < PTP3_CFG_CPU_START_ID_B) {
addr = ptp3_cfg3[PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
value = ptp3_cfg3[PTP3_CFG_VALUE];
} else {
addr = ptp3_cfg3_ext[PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
value = ptp3_cfg3_ext[PTP3_CFG_VALUE];
}
mmio_write_32(addr, value & PTP3_CFG3_MASK1);
mmio_write_32(addr, value & PTP3_CFG3_MASK2);
mmio_write_32(addr, value & PTP3_CFG3_MASK3);
}
static void pdp_proc_arm_write(unsigned int pdp_n)
{
unsigned long v = 0;
dsb();
__asm__ volatile ("mrs %0, S3_6_C15_C2_0" : "=r" (v));
v |= (UL(0x0) << 52);
v |= (UL(0x1) << 53);
v |= (UL(0x0) << 54);
v |= (UL(0x0) << 48);
v |= (UL(0x1) << 49);
__asm__ volatile ("msr S3_6_C15_C2_0, %0" : : "r" (v));
dsb();
}
static void pdp_init(unsigned int pdp_cpu)
{
if ((pdp_cpu >= PTP3_CFG_CPU_START_ID_B) && (pdp_cpu < NR_PTP3_CFG_CPU)) {
pdp_proc_arm_write(pdp_cpu);
}
}
void ptp3_core_init(unsigned int core)
{
ptp3_init(core);
pdp_init(core);
}
void ptp3_core_deinit(unsigned int core)
{
/* TBD */
}
#if MTK_PUBEVENT_ENABLE
/* Handle for power on domain */
void *ptp3_handle_pwr_on_event(const void *arg)
{
if (arg != NULL) {
struct mt_cpupm_event_data *data = (struct mt_cpupm_event_data *)arg;
if ((data->pwr_domain & MT_CPUPM_PWR_DOMAIN_CORE) > 0) {
ptp3_core_init(data->cpuid);
}
}
return (void *)arg;
}
MT_CPUPM_SUBCRIBE_EVENT_PWR_ON(ptp3_handle_pwr_on_event);
/* Handle for power off domain */
void *ptp3_handle_pwr_off_event(const void *arg)
{
if (arg != NULL) {
struct mt_cpupm_event_data *data = (struct mt_cpupm_event_data *)arg;
if ((data->pwr_domain & MT_CPUPM_PWR_DOMAIN_CORE) > 0) {
ptp3_core_deinit(data->cpuid);
}
}
return (void *)arg;
}
MT_CPUPM_SUBCRIBE_EVENT_PWR_OFF(ptp3_handle_pwr_off_event);
#else
#pragma message "PSCI hint not enable"
#endif
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PTP3_COMMON_H
#define PTP3_COMMON_H
/* config enum */
enum PTP3_CFG {
PTP3_CFG_ADDR,
PTP3_CFG_VALUE,
NR_PTP3_CFG,
};
/* prototype */
void ptp3_core_init(unsigned int core);
void ptp3_core_deinit(unsigned int core);
#endif /* PTP3_COMMON_H */
@@ -0,0 +1,16 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := mtk_ptp3
LOCAL_SRCS-y := ${LOCAL_DIR}/ptp3_common.c
PLAT_INCLUDES += -I${LOCAL_DIR}
PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef RTC_H
#define RTC_H
#include <rtc_mt6359p.h>
#endif /* RTC_H */
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2019-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <pmic_wrap_init.h>
#include <rtc.h>
/* RTC busy status polling interval and retry count */
enum {
RTC_WRTGR_POLLING_DELAY_MS = 10,
RTC_WRTGR_POLLING_CNT = 100
};
uint16_t RTC_Read(uint32_t addr)
{
uint32_t rdata = 0;
pwrap_read((uint32_t)addr, &rdata);
return (uint16_t)rdata;
}
void RTC_Write(uint32_t addr, uint16_t data)
{
pwrap_write((uint32_t)addr, (uint32_t)data);
}
int32_t rtc_busy_wait(void)
{
uint64_t retry = RTC_WRTGR_POLLING_CNT;
do {
mdelay(RTC_WRTGR_POLLING_DELAY_MS);
if (!(RTC_Read(RTC_BBPU) & RTC_BBPU_CBUSY))
return 1;
retry--;
} while (retry);
ERROR("[RTC] rtc cbusy time out!\n");
return 0;
}
int32_t RTC_Write_Trigger(void)
{
RTC_Write(RTC_WRTGR, 1);
return rtc_busy_wait();
}
int32_t Writeif_unlock(void)
{
RTC_Write(RTC_PROT, RTC_PROT_UNLOCK1);
if (!RTC_Write_Trigger())
return 0;
RTC_Write(RTC_PROT, RTC_PROT_UNLOCK2);
if (!RTC_Write_Trigger())
return 0;
return 1;
}
@@ -0,0 +1,148 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <rtc.h>
static void RTC_Config_Interface(uint32_t addr, uint16_t data,
uint16_t mask, uint16_t shift)
{
uint16_t pmic_reg;
pmic_reg = RTC_Read(addr);
pmic_reg &= ~(mask << shift);
pmic_reg |= (data << shift);
RTC_Write(addr, pmic_reg);
}
static int32_t rtc_disable_2sec_reboot(void)
{
uint16_t reboot;
reboot = (RTC_Read(RTC_AL_SEC) & ~RTC_BBPU_2SEC_EN) &
~RTC_BBPU_AUTO_PDN_SEL;
RTC_Write(RTC_AL_SEC, reboot);
return RTC_Write_Trigger();
}
static int32_t rtc_enable_k_eosc(void)
{
uint16_t alm_dow, alm_sec;
int16_t ret;
/* Turning on eosc cali mode clock */
RTC_Config_Interface(PMIC_RG_SCK_TOP_CKPDN_CON0_CLR, 1,
PMIC_RG_RTC_EOSC32_CK_PDN_MASK,
PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT);
alm_sec = RTC_Read(RTC_AL_SEC) & (~RTC_LPD_OPT_MASK);
RTC_Write(RTC_AL_SEC, alm_sec);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
RTC_Write(RTC_CON, RTC_LPD_EN);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
RTC_Write(RTC_CON, RTC_LPD_RST);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
RTC_Write(RTC_CON, RTC_LPD_EN);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
RTC_Write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
RTC_Write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
/* set RTC EOSC calibration period = 8sec */
alm_dow = (RTC_Read(RTC_AL_DOW) & (~RTC_RG_EOSC_CALI_TD_MASK)) |
RTC_RG_EOSC_CALI_TD_8SEC;
RTC_Write(RTC_AL_DOW, alm_dow);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
RTC_Write(RTC_BBPU,
RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
/* Enable K EOSC mode :use solution1 of eosc cali to fix mt6359p 32K*/
RTC_Write(RTC_AL_YEA, (((RTC_Read(RTC_AL_YEA) | RTC_K_EOSC_RSV_0)
& (~RTC_K_EOSC_RSV_1)) | (RTC_K_EOSC_RSV_2)));
ret = RTC_Write_Trigger();
if (ret == 0) {
return 0;
}
INFO("[RTC] RTC_enable_k_eosc\n");
return 1;
}
void rtc_power_off_sequence(void)
{
uint16_t bbpu;
int16_t ret;
ret = rtc_disable_2sec_reboot();
if (ret == 0) {
return;
}
ret = rtc_enable_k_eosc();
if (ret == 0) {
return;
}
bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN;
if (Writeif_unlock() != 0) {
RTC_Write(RTC_BBPU,
bbpu | RTC_BBPU_RESET_ALARM | RTC_BBPU_RESET_SPAR);
RTC_Write(RTC_AL_MASK, RTC_AL_MASK_DOW);
ret = RTC_Write_Trigger();
if (ret == 0) {
return;
}
mdelay(1);
bbpu = RTC_Read(RTC_BBPU);
if (((bbpu & RTC_BBPU_RESET_ALARM) > 0) ||
((bbpu & RTC_BBPU_RESET_SPAR) > 0)) {
INFO("[RTC] timeout\n");
}
bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
RTC_Write(RTC_BBPU, bbpu);
ret = RTC_Write_Trigger();
if (ret == 0) {
return;
}
}
}
@@ -0,0 +1,197 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef RTC_MT6359P_H
#define RTC_MT6359P_H
/* RTC registers */
enum {
RTC_BBPU = 0x0588,
RTC_IRQ_STA = 0x058A,
RTC_IRQ_EN = 0x058C,
RTC_CII_EN = 0x058E
};
enum {
RTC_AL_SEC = 0x05A0,
RTC_AL_MIN = 0x05A2,
RTC_AL_HOU = 0x05A4,
RTC_AL_DOM = 0x05A6,
RTC_AL_DOW = 0x05A8,
RTC_AL_MTH = 0x05AA,
RTC_AL_YEA = 0x05AC,
RTC_AL_MASK = 0x0590
};
enum {
RTC_OSC32CON = 0x05AE,
RTC_CON = 0x05C4,
RTC_WRTGR = 0x05C2
};
enum {
RTC_POWERKEY1 = 0x05B0,
RTC_POWERKEY2 = 0x05B2
};
enum {
RTC_POWERKEY1_KEY = 0xA357,
RTC_POWERKEY2_KEY = 0x67D2
};
enum {
RTC_PDN1 = 0x05B4,
RTC_PDN2 = 0x05B6,
RTC_SPAR0 = 0x05B8,
RTC_SPAR1 = 0x05BA,
RTC_PROT = 0x05BC,
RTC_DIFF = 0x05BE,
RTC_CALI = 0x05C0
};
enum {
RTC_OSC32CON_UNLOCK1 = 0x1A57,
RTC_OSC32CON_UNLOCK2 = 0x2B68
};
enum {
RTC_LPD_EN = 0x0406,
RTC_LPD_RST = 0x040E
};
enum {
RTC_LPD_OPT_XOSC_AND_EOSC_LPD = 0U << 13,
RTC_LPD_OPT_EOSC_LPD = 1U << 13,
RTC_LPD_OPT_XOSC_LPD = 2U << 13,
RTC_LPD_OPT_F32K_CK_ALIVE = 3U << 13,
};
#define RTC_LPD_OPT_MASK (3U << 13)
enum {
RTC_PROT_UNLOCK1 = 0x586A,
RTC_PROT_UNLOCK2 = 0x9136
};
enum {
RTC_BBPU_PWREN = 1U << 0,
RTC_BBPU_SPAR_SW = 1U << 1,
RTC_BBPU_RESET_SPAR = 1U << 2,
RTC_BBPU_RESET_ALARM = 1U << 3,
RTC_BBPU_CLRPKY = 1U << 4,
RTC_BBPU_RELOAD = 1U << 5,
RTC_BBPU_CBUSY = 1U << 6
};
enum {
RTC_AL_MASK_SEC = 1U << 0,
RTC_AL_MASK_MIN = 1U << 1,
RTC_AL_MASK_HOU = 1U << 2,
RTC_AL_MASK_DOM = 1U << 3,
RTC_AL_MASK_DOW = 1U << 4,
RTC_AL_MASK_MTH = 1U << 5,
RTC_AL_MASK_YEA = 1U << 6
};
enum {
RTC_BBPU_AUTO_PDN_SEL = 1U << 6,
RTC_BBPU_2SEC_CK_SEL = 1U << 7,
RTC_BBPU_2SEC_EN = 1U << 8,
RTC_BBPU_2SEC_MODE = 0x3 << 9,
RTC_BBPU_2SEC_STAT_CLEAR = 1U << 11,
RTC_BBPU_2SEC_STAT_STA = 1U << 12
};
enum {
RTC_BBPU_KEY = 0x43 << 8
};
enum {
RTC_EMBCK_SRC_SEL = 1 << 8,
RTC_EMBCK_SEL_MODE = 3 << 6,
RTC_XOSC32_ENB = 1 << 5,
RTC_REG_XOSC32_ENB = 1 << 15
};
enum {
RTC_K_EOSC_RSV_0 = 1 << 8,
RTC_K_EOSC_RSV_1 = 1 << 9,
RTC_K_EOSC_RSV_2 = 1 << 10
};
enum {
RTC_RG_EOSC_CALI_TD_1SEC = 3 << 5,
RTC_RG_EOSC_CALI_TD_2SEC = 4 << 5,
RTC_RG_EOSC_CALI_TD_4SEC = 5 << 5,
RTC_RG_EOSC_CALI_TD_8SEC = 6 << 5,
RTC_RG_EOSC_CALI_TD_16SEC = 7 << 5,
RTC_RG_EOSC_CALI_TD_MASK = 7 << 5
};
/* PMIC TOP Register Definition */
enum {
PMIC_RG_TOP_CON = 0x0020,
PMIC_RG_TOP_CKPDN_CON1 = 0x0112,
PMIC_RG_TOP_CKPDN_CON1_SET = 0x0114,
PMIC_RG_TOP_CKPDN_CON1_CLR = 0x0116,
PMIC_RG_TOP_CKSEL_CON0 = 0x0118,
PMIC_RG_TOP_CKSEL_CON0_SET = 0x011A,
PMIC_RG_TOP_CKSEL_CON0_CLR = 0x011C
};
/* PMIC SCK Register Definition */
enum {
PMIC_RG_SCK_TOP_CKPDN_CON0 = 0x0514,
PMIC_RG_SCK_TOP_CKPDN_CON0_SET = 0x0516,
PMIC_RG_SCK_TOP_CKPDN_CON0_CLR = 0x0518,
PMIC_RG_EOSC_CALI_CON0 = 0x53A
};
enum {
PMIC_EOSC_CALI_START_ADDR = 0x53A
};
enum {
PMIC_EOSC_CALI_START_MASK = 0x1,
PMIC_EOSC_CALI_START_SHIFT = 0
};
/* PMIC DCXO Register Definition */
enum {
PMIC_RG_DCXO_CW00 = 0x0788,
PMIC_RG_DCXO_CW02 = 0x0790,
PMIC_RG_DCXO_CW08 = 0x079C,
PMIC_RG_DCXO_CW09 = 0x079E,
PMIC_RG_DCXO_CW09_CLR = 0x07A2,
PMIC_RG_DCXO_CW10 = 0x07A4,
PMIC_RG_DCXO_CW12 = 0x07A8,
PMIC_RG_DCXO_CW13 = 0x07AA,
PMIC_RG_DCXO_CW15 = 0x07AE,
PMIC_RG_DCXO_CW19 = 0x07B6,
};
enum {
PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK = 0x1,
PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT = 1,
PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK = 0x1,
PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT = 3,
PMIC_RG_RTC_EOSC32_CK_PDN_MASK = 0x1,
PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT = 2,
PMIC_RG_EOSC_CALI_TD_MASK = 0x7,
PMIC_RG_EOSC_CALI_TD_SHIFT = 5,
PMIC_RG_XO_EN32K_MAN_MASK = 0x1,
PMIC_RG_XO_EN32K_MAN_SHIFT = 0
};
/* external API */
uint16_t RTC_Read(uint32_t addr);
void RTC_Write(uint32_t addr, uint16_t data);
int32_t rtc_busy_wait(void);
int32_t RTC_Write_Trigger(void);
int32_t Writeif_unlock(void);
void rtc_power_off_sequence(void);
#endif /* RTC_MT6359P_H */
@@ -0,0 +1,20 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := rtc
LOCAL_SRCS-y := ${LOCAL_DIR}/rtc_common.c
ifeq (${USE_RTC_MT6359P}, 1)
LOCAL_SRCS-y += ${LOCAL_DIR}/rtc_mt6359p.c
PLAT_INCLUDES += -I${LOCAL_DIR}
endif
PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/mtk_init/mtk_init.h>
#include <mt_timer.h>
#include <platform_def.h>
uint64_t normal_time_base;
uint64_t atf_time_base;
void sched_clock_init(uint64_t normal_base, uint64_t atf_base)
{
normal_time_base += normal_base;
atf_time_base = atf_base;
}
uint64_t sched_clock(void)
{
uint64_t cval;
uint64_t rel_base;
rel_base = read_cntpct_el0() - atf_time_base;
cval = ((rel_base * 1000U) / SYS_COUNTER_FREQ_IN_MHZ)
- normal_time_base;
return cval;
}
int mt_systimer_init(void)
{
INFO("[%s] systimer initialization\n", __func__);
/* Enable access in NS mode */
mmio_write_32(CNTWACR_REG, CNT_WRITE_ACCESS_CTL_MASK);
mmio_write_32(CNTRACR_REG, CNT_READ_ACCESS_CTL_MASK);
return 0;
}
MTK_PLAT_SETUP_0_INIT(mt_systimer_init);
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_TIMER_H
#define MT_TIMER_H
#define SYSTIMER_BASE (0x10017000)
#define CNTCR_REG (SYSTIMER_BASE + 0x0)
#define CNTSR_REG (SYSTIMER_BASE + 0x4)
#define CNTSYS_L_REG (SYSTIMER_BASE + 0x8)
#define CNTSYS_H_REG (SYSTIMER_BASE + 0xc)
#define CNTWACR_REG (SYSTIMER_BASE + 0x10)
#define CNTRACR_REG (SYSTIMER_BASE + 0x14)
#define TIEO_EN (1 << 3)
#define COMP_15_EN (1 << 10)
#define COMP_20_EN (1 << 11)
#define COMP_25_EN (1 << 12)
#define COMP_FEATURE_MASK (COMP_15_EN | COMP_20_EN | COMP_25_EN | TIEO_EN)
#define COMP_15_MASK (COMP_15_EN)
#define COMP_20_MASK (COMP_20_EN | TIEO_EN)
#define COMP_25_MASK (COMP_20_EN | COMP_25_EN)
#define CNT_WRITE_ACCESS_CTL_MASK (0x3FFFFF0U)
#define CNT_READ_ACCESS_CTL_MASK (0x3FFFFFFU)
void sched_clock_init(uint64_t normal_base, uint64_t atf_base);
uint64_t sched_clock(void);
int mt_systimer_init(void);
#endif /* MT_TIMER_H */
@@ -0,0 +1,14 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := timer
LOCAL_SRCS-y := $(LOCAL_DIR)/mt_timer.c
PLAT_INCLUDES += -I${LOCAL_DIR}
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,163 @@
/*
* Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <uart8250.h>
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
/* -----------------------------------------------
* int console_core_init(unsigned long base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success else 0 on error
* Clobber list : x1, x2, x3
* -----------------------------------------------
*/
func console_core_init
/* Check the input base address */
cbz x0, core_init_fail
/* Check baud rate and uart clock for sanity */
cbz w1, core_init_fail
cbz w2, core_init_fail
/* Disable interrupt */
str wzr, [x0, #UART_IER]
/* Force DTR and RTS to high */
mov w3, #(UART_MCR_DTR | UART_MCR_RTS)
str w3, [x0, #UART_MCR]
/* Check high speed */
movz w3, #:abs_g1:115200
movk w3, #:abs_g0_nc:115200
cmp w2, w3
b.hi 1f
/* Non high speed */
lsl w2, w2, #4
mov w3, wzr
b 2f
/* High speed */
1: lsl w2, w2, #2
mov w3, #2
/* Set high speed UART register */
2: str w3, [x0, #UART_HIGHSPEED]
/* Calculate divisor */
udiv w3, w1, w2 /* divisor = uartclk / (quot * baudrate) */
msub w1, w3, w2, w1 /* remainder = uartclk % (quot * baudrate) */
lsr w2, w2, #1
cmp w1, w2
cinc w3, w3, hs
/* Set line configuration, access divisor latches */
mov w1, #(UART_LCR_DLAB | UART_LCR_WLS_8)
str w1, [x0, #UART_LCR]
/* Set the divisor */
and w1, w3, #0xff
str w1, [x0, #UART_DLL]
lsr w1, w3, #8
and w1, w1, #0xff
str w1, [x0, #UART_DLH]
/* Hide the divisor latches */
mov w1, #UART_LCR_WLS_8
str w1, [x0, #UART_LCR]
/* Enable FIFOs, and clear receive and transmit */
mov w1, #(UART_FCR_FIFO_EN | UART_FCR_CLEAR_RCVR | \
UART_FCR_CLEAR_XMIT)
str w1, [x0, #UART_FCR]
mov w0, #1
ret
core_init_fail:
mov w0, wzr
ret
endfunc console_core_init
/* --------------------------------------------------------
* int console_core_putc(int c, unsigned long base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - console base address
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
/* Check if the transmit FIFO is full */
1: ldr w2, [x1, #UART_LSR]
and w2, w2, #UART_LSR_THRE
cbz w2, 1b
mov w2, #0xD
str w2, [x1, #UART_THR]
/* Check if the transmit FIFO is full */
2: ldr w2, [x1, #UART_LSR]
and w2, w2, #UART_LSR_THRE
cbz w2, 2b
str w0, [x1, #UART_THR]
ret
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
/* ---------------------------------------------
* int console_core_getc(unsigned long base_addr)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* In : x0 - console base address
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
cbz x0, getc_error
/* Check if the receive FIFO is empty */
1: ldr w1, [x0, #UART_LSR]
tbz w1, #UART_LSR_DR, 1b
ldr w0, [x0, #UART_RBR]
ret
getc_error:
mov w0, #-1
ret
endfunc console_core_getc
/* ---------------------------------------------
* void console_core_flush(uintptr_t base_addr)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
* Out : void.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_flush
/* Placeholder */
ret
endfunc console_core_flush
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <uart.h>
static struct mt_uart uart_save_addr[DRV_SUPPORT_UART_PORTS];
static const uint32_t uart_base_addr[DRV_SUPPORT_UART_PORTS] = {
UART0_BASE,
UART1_BASE
};
void mt_uart_restore(void)
{
int uart_idx = UART_PORT0;
struct mt_uart *uart;
unsigned long base;
/* Must NOT print any debug log before UART restore */
for (uart_idx = UART_PORT0; uart_idx < HW_SUPPORT_UART_PORTS;
uart_idx++) {
uart = &uart_save_addr[uart_idx];
base = uart->base;
mmio_write_32(UART_LCR(base), UART_LCR_MODE_B);
mmio_write_32(UART_EFR(base), uart->registers.efr);
mmio_write_32(UART_LCR(base), uart->registers.lcr);
mmio_write_32(UART_FCR(base), uart->registers.fcr);
/* baudrate */
mmio_write_32(UART_HIGHSPEED(base), uart->registers.highspeed);
mmio_write_32(UART_FRACDIV_L(base), uart->registers.fracdiv_l);
mmio_write_32(UART_FRACDIV_M(base), uart->registers.fracdiv_m);
mmio_write_32(UART_LCR(base),
uart->registers.lcr | UART_LCR_DLAB);
mmio_write_32(UART_DLL(base), uart->registers.dll);
mmio_write_32(UART_DLH(base), uart->registers.dlh);
mmio_write_32(UART_LCR(base), uart->registers.lcr);
mmio_write_32(UART_SAMPLE_COUNT(base),
uart->registers.sample_count);
mmio_write_32(UART_SAMPLE_POINT(base),
uart->registers.sample_point);
mmio_write_32(UART_GUARD(base), uart->registers.guard);
/* flow control */
mmio_write_32(UART_ESCAPE_EN(base), uart->registers.escape_en);
mmio_write_32(UART_MCR(base), uart->registers.mcr);
mmio_write_32(UART_IER(base), uart->registers.ier);
mmio_write_32(UART_SCR(base), uart->registers.scr);
}
}
void mt_uart_save(void)
{
int uart_idx = UART_PORT0;
struct mt_uart *uart;
unsigned long base;
for (uart_idx = UART_PORT0; uart_idx < HW_SUPPORT_UART_PORTS;
uart_idx++) {
uart_save_addr[uart_idx].base = uart_base_addr[uart_idx];
base = uart_base_addr[uart_idx];
uart = &uart_save_addr[uart_idx];
uart->registers.lcr = mmio_read_32(UART_LCR(base));
mmio_write_32(UART_LCR(base), UART_LCR_MODE_B);
uart->registers.efr = mmio_read_32(UART_EFR(base));
mmio_write_32(UART_LCR(base), uart->registers.lcr);
uart->registers.fcr = mmio_read_32(UART_FCR_RD(base));
/* baudrate */
uart->registers.highspeed = mmio_read_32(UART_HIGHSPEED(base));
uart->registers.fracdiv_l = mmio_read_32(UART_FRACDIV_L(base));
uart->registers.fracdiv_m = mmio_read_32(UART_FRACDIV_M(base));
mmio_write_32(UART_LCR(base),
uart->registers.lcr | UART_LCR_DLAB);
uart->registers.dll = mmio_read_32(UART_DLL(base));
uart->registers.dlh = mmio_read_32(UART_DLH(base));
mmio_write_32(UART_LCR(base), uart->registers.lcr);
uart->registers.sample_count = mmio_read_32(
UART_SAMPLE_COUNT(base));
uart->registers.sample_point = mmio_read_32(
UART_SAMPLE_POINT(base));
uart->registers.guard = mmio_read_32(UART_GUARD(base));
/* flow control */
uart->registers.escape_en = mmio_read_32(UART_ESCAPE_EN(base));
uart->registers.mcr = mmio_read_32(UART_MCR(base));
uart->registers.ier = mmio_read_32(UART_IER(base));
uart->registers.scr = mmio_read_32(UART_SCR(base));
}
}
void mt_console_uart_cg(int on)
{
if (on == 1) {
mmio_write_32(UART_CLOCK_GATE_CLR, UART0_CLOCK_GATE_BIT);
} else {
mmio_write_32(UART_CLOCK_GATE_SET, UART0_CLOCK_GATE_BIT);
}
}
uint32_t mt_console_uart_cg_status(void)
{
return mmio_read_32(UART_CLOCK_GATE_STA) & UART0_CLOCK_GATE_BIT;
}
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef UART_H
#define UART_H
#include <platform_def.h>
/* UART HW information */
#define HW_SUPPORT_UART_PORTS 2
#define DRV_SUPPORT_UART_PORTS 2
/* console UART clock cg */
#define UART_CLOCK_GATE_SET (INFRACFG_AO_BASE + 0x80)
#define UART_CLOCK_GATE_CLR (INFRACFG_AO_BASE + 0x84)
#define UART_CLOCK_GATE_STA (INFRACFG_AO_BASE + 0x90)
#define UART0_CLOCK_GATE_BIT (1U<<22)
#define UART1_CLOCK_GATE_BIT (1U<<23)
/* UART registers */
#define UART_RBR(_baseaddr) (_baseaddr + 0x0)
#define UART_THR(_baseaddr) (_baseaddr + 0x0)
#define UART_IER(_baseaddr) (_baseaddr + 0x4)
#define UART_IIR(_baseaddr) (_baseaddr + 0x8)
#define UART_FCR(_baseaddr) (_baseaddr + 0x8)
#define UART_LCR(_baseaddr) (_baseaddr + 0xc)
#define UART_MCR(_baseaddr) (_baseaddr + 0x10)
#define UART_LSR(_baseaddr) (_baseaddr + 0x14)
#define UART_MSR(_baseaddr) (_baseaddr + 0x18)
#define UART_SCR(_baseaddr) (_baseaddr + 0x1c)
#define UART_DLL(_baseaddr) (_baseaddr + 0x0)
#define UART_DLH(_baseaddr) (_baseaddr + 0x4)
#define UART_EFR(_baseaddr) (_baseaddr + 0x8)
#define UART_XON1(_baseaddr) (_baseaddr + 0x10)
#define UART_XON2(_baseaddr) (_baseaddr + 0x14)
#define UART_XOFF1(_baseaddr) (_baseaddr + 0x18)
#define UART_XOFF2(_baseaddr) (_baseaddr + 0x1c)
#define UART_AUTOBAUD(_baseaddr) (_baseaddr + 0x20)
#define UART_HIGHSPEED(_baseaddr) (_baseaddr + 0x24)
#define UART_SAMPLE_COUNT(_baseaddr) (_baseaddr + 0x28)
#define UART_SAMPLE_POINT(_baseaddr) (_baseaddr + 0x2c)
#define UART_AUTOBAUD_REG(_baseaddr) (_baseaddr + 0x30)
#define UART_RATE_FIX_REG(_baseaddr) (_baseaddr + 0x34)
#define UART_AUTO_BAUDSAMPLE(_baseaddr) (_baseaddr + 0x38)
#define UART_GUARD(_baseaddr) (_baseaddr + 0x3c)
#define UART_ESCAPE_DAT(_baseaddr) (_baseaddr + 0x40)
#define UART_ESCAPE_EN(_baseaddr) (_baseaddr + 0x44)
#define UART_SLEEP_EN(_baseaddr) (_baseaddr + 0x48)
#define UART_DMA_EN(_baseaddr) (_baseaddr + 0x4c)
#define UART_RXTRI_AD(_baseaddr) (_baseaddr + 0x50)
#define UART_FRACDIV_L(_baseaddr) (_baseaddr + 0x54)
#define UART_FRACDIV_M(_baseaddr) (_baseaddr + 0x58)
#define UART_FCR_RD(_baseaddr) (_baseaddr + 0x5C)
#define UART_USB_RX_SEL(_baseaddr) (_baseaddr + 0xB0)
#define UART_SLEEP_REQ(_baseaddr) (_baseaddr + 0xB4)
#define UART_SLEEP_ACK(_baseaddr) (_baseaddr + 0xB8)
#define UART_SPM_SEL(_baseaddr) (_baseaddr + 0xBC)
#define UART_LCR_DLAB 0x0080
#define UART_LCR_MODE_B 0x00bf
enum uart_port_ID {
UART_PORT0 = 0,
UART_PORT1
};
struct mt_uart_register {
uint32_t dll;
uint32_t dlh;
uint32_t ier;
uint32_t lcr;
uint32_t mcr;
uint32_t fcr;
uint32_t lsr;
uint32_t scr;
uint32_t efr;
uint32_t highspeed;
uint32_t sample_count;
uint32_t sample_point;
uint32_t fracdiv_l;
uint32_t fracdiv_m;
uint32_t escape_en;
uint32_t guard;
uint32_t rx_sel;
};
struct mt_uart {
unsigned long base;
struct mt_uart_register registers;
};
/* external API */
void mt_uart_save(void);
void mt_uart_restore(void);
void mt_console_uart_cg(int on);
uint32_t mt_console_uart_cg_status(void);
#endif /* __UART_H__ */
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef UART8250_H
#define UART8250_H
/* UART register */
#define UART_RBR 0x00 /* Receive buffer register */
#define UART_DLL 0x00 /* Divisor latch lsb */
#define UART_THR 0x00 /* Transmit holding register */
#define UART_DLH 0x04 /* Divisor latch msb */
#define UART_IER 0x04 /* Interrupt enable register */
#define UART_FCR 0x08 /* FIFO control register */
#define UART_LCR 0x0c /* Line control register */
#define UART_MCR 0x10 /* Modem control register */
#define UART_LSR 0x14 /* Line status register */
#define UART_HIGHSPEED 0x24 /* High speed UART */
/* FCR */
#define UART_FCR_FIFO_EN 0x01 /* enable FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* clear the XMIT FIFO */
/* LCR */
#define UART_LCR_WLS_8 0x03 /* 8 bit character length */
#define UART_LCR_DLAB 0x80 /* divisor latch access bit */
/* MCR */
#define UART_MCR_DTR 0x01
#define UART_MCR_RTS 0x02
/* LSR */
#define UART_LSR_DR 0x01 /* Data ready */
#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
#endif /* UART8250_H */
@@ -0,0 +1,118 @@
/*
* Copyright (c) 2022, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <cpu_macros.S>
#if CONFIG_MTK_MCUSYS
#include <mcucfg.h>
#endif
#include <platform_def.h>
/*
* Declare as weak function so that can be
* overwritten by platform helpers
*/
.weak platform_mem_init
.weak plat_core_pos_by_mpidr
.weak plat_my_core_pos
.weak plat_mediatek_calc_core_pos
.global plat_mpidr_by_core_pos
.global plat_reset_handler
/* -----------------------------------------------------
* unsigned long plat_mpidr_by_core_pos(uint32_t cpuid)
* This function calcuate mpidr by cpu pos if cpu
* topology is linear.
*
* Clobbers: x0-x1
* -----------------------------------------------------
*/
func plat_mpidr_by_core_pos
lsl x0, x0, #MPIDR_AFF1_SHIFT
mrs x1, mpidr_el1
and x1, x1, #MPIDR_MT_MASK
orr x0, x0, x1
ret
endfunc plat_mpidr_by_core_pos
/* -----------------------------------------------------
* unsigned int plat_my_core_pos(void)
* This function uses the plat_arm_calc_core_pos()
* definition to get the index of the calling CPU.
* -----------------------------------------------------
*/
func plat_my_core_pos
mrs x0, mpidr_el1
b plat_mediatek_calc_core_pos
endfunc plat_my_core_pos
/* -----------------------------------------------------
* int plat_mediatek_calc_core_pos(u_register_t mpidr);
*
* In ARMv8.2, AFF2 is cluster id, AFF1 is core id and
* AFF0 is thread id. There is only one cluster in ARMv8.2
* and one thread in current implementation.
*
* With this function: CorePos = CoreID (AFF1)
* we do it with x0 = (x0 >> 8) & 0xff
* -----------------------------------------------------
*/
func plat_mediatek_calc_core_pos
b plat_core_pos_by_mpidr
endfunc plat_mediatek_calc_core_pos
/* ------------------------------------------------------
* int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
*
* This function implements a part of the critical
* interface between the psci generic layer and the
* platform that allows the former to query the platform
* to convert an MPIDR to a unique linear index.
*
* Clobbers: x0-x1
* ------------------------------------------------------
*/
func plat_core_pos_by_mpidr
mov x1, #MPIDR_AFFLVL_MASK
and x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
ret
endfunc plat_core_pos_by_mpidr
/* --------------------------------------------------------
* void platform_mem_init (void);
*
* Any memory init, relocation to be done before the
* platform boots. Called very early in the boot process.
* --------------------------------------------------------
*/
func platform_mem_init
ret
endfunc platform_mem_init
func plat_reset_handler
#if CONFIG_MTK_MCUSYS
mov x10, x30
bl plat_my_core_pos
mov x30, x10
mov w1, #0x1
lsl w1, w1, w0
ldr x0, =CPC_MCUSYS_CPU_ON_SW_HINT_SET
str w1, [x0]
dsb sy
#endif
#if CONFIG_MTK_ECC
mov x10, x30
/* enable sequence of ecc for cpus */
bl disable_core_ecc
bl ft_ecc_clear_per_core
bl enable_core_ecc
mov x30, x10
#endif
ret
endfunc plat_reset_handler
@@ -0,0 +1,12 @@
#
# Copyright (c) 2022, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
LOCAL_DIR := $(call GET_LOCAL_DIR)
MODULE := helpers
LOCAL_SRCS-y += $(LOCAL_DIR)/$(ARCH_VERSION)/arch_helpers.S
$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2022, Mediatek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef ARCH_DEF_H
#define ARCH_DEF_H
/* Topology constants */
#define PLAT_MAX_PWR_LVL (2)
#define PLAT_MAX_RET_STATE (1)
#define PLAT_MAX_OFF_STATE (2)
#define PLATFORM_SYSTEM_COUNT (1)
#define PLATFORM_CLUSTER_COUNT (1)
#define PLATFORM_CLUSTER0_CORE_COUNT (8)
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
#define PLATFORM_MAX_CPUS_PER_CLUSTER (8)
#define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \
PLATFORM_CLUSTER_COUNT + \
PLATFORM_CORE_COUNT)
/*******************************************************************************
* Declarations and constants to access the mailboxes safely. Each mailbox is
* aligned on the biggest cache line size in the platform. This is known only
* to the platform as it might have a combination of integrated and external
* caches. Such alignment ensures that two maiboxes do not sit on the same cache
* line at any cache level. They could belong to different cpus/clusters &
* get written while being protected by different locks causing corruption of
* a valid mailbox address.
******************************************************************************/
/* Cachline size */
#define CACHE_WRITEBACK_SHIFT (6)
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
#endif /* ARCH_DEF_H */

Some files were not shown because too many files have changed in this diff Show More