diff options
48 files changed, 3707 insertions, 487 deletions
diff --git a/docs/resources/diagrams/plantuml/fip-secure-partitions.puml b/docs/resources/diagrams/plantuml/fip-secure-partitions.puml index 40621dbed..9457e326a 100644 --- a/docs/resources/diagrams/plantuml/fip-secure-partitions.puml +++ b/docs/resources/diagrams/plantuml/fip-secure-partitions.puml @@ -13,6 +13,7 @@ folder SP_vendor_1 { === UUID = xxx load_address = 0xaaa + owner = "Sip" ... ] } @@ -24,9 +25,26 @@ folder SP_vendor_2 { === UUID = yyy load_address = 0xbbb + owner = "Plat" ] } +artifact tb_fw_config.dts [ + tb_fw_config.dts + ---- + secure-partitions + === + spkg_1 UUID + spkg_1 load_address + --- + spkg_2 UUID + spkg_2 load_address + --- + ... + === + ...<rest of the nodes> +] + artifact config.json [ SP_LAYOUT.json === @@ -41,31 +59,22 @@ artifact config.json [ control sp_mk_generator -artifact fconf_node [ - fconf_sp.dts - === - spkg_1 UUID - spkg_1 load_address - --- - spkg_2 UUID - spkg_2 load_address -] - artifact sp_gen [ sp_gen.mk === FDT_SOURCE = ... SPTOOL_ARGS = ... - FIP_ARG = ... + FIP_ARGS = ... + CRT_ARGS = ... ] control dtc control sptool -artifact FW_CONFIG +artifact tb_fw_config.dtb artifact spkg_1 [ - spkg_1.bin + sp1.pkg === <i>header</i> --- @@ -75,27 +84,56 @@ artifact spkg_1 [ ] artifact spkg_2 [ - spkg_2.bin + sp2.pkg + === + <i>header</i> + --- + manifest + --- + binary +] + +artifact signed_tb_fw_config.dtb [ + tb_fw_config.dtb (signed) +] + +artifact signed_spkg_1 [ + sp1.pkg (signed) + === + <i>header</i> + --- + manifest + --- + binary + --- + <i>signature</I> +] + +artifact signed_spkg_2 [ + sp2.pkg (signed) === <i>header</i> --- manifest --- binary + --- + <i>signature</I> ] +control crttool control fiptool artifact fip [ fip.bin === - FW_CONFIG.dtb + tb_fw_config.dtb (signed) --- ... --- - SPKG1 + sp1.pkg (signed & SiP owned) --- - SPKG2 + sp2.pkg (signed & Platform owned) --- ... ] @@ -103,20 +141,27 @@ artifact fip [ config.json .up.> SP_vendor_1 config.json .up.> SP_vendor_2 config.json --> sp_mk_generator -sp_mk_generator --> fconf_node sp_mk_generator --> sp_gen - +sp_gen --> fiptool +sp_gen --> cert_create sp_gen --> sptool + sptool --> spkg_1 sptool --> spkg_2 -fconf_node -down-> dtc -dtc --> FW_CONFIG +spkg_1 --> cert_create +spkg_2 --> cert_create +cert_create --> signed_spkg_1 +cert_create --> signed_spkg_2 -sp_gen --> fiptool -FW_CONFIG --> fiptool -spkg_1 -down-> fiptool -spkg_2 -down-> fiptool +tb_fw_config.dts --> dtc +dtc --> tb_fw_config.dtb +tb_fw_config.dtb --> cert_create +cert_create --> signed_tb_fw_config.dtb + +signed_tb_fw_config.dtb --> fiptool +signed_spkg_1 -down-> fiptool +signed_spkg_2 -down-> fiptool fiptool -down-> fip @enduml diff --git a/drivers/renesas/rcar/console/rcar_printf.c b/drivers/renesas/rcar/console/rcar_printf.c index e75b9f454..ad074fe05 100644 --- a/drivers/renesas/rcar/console/rcar_printf.c +++ b/drivers/renesas/rcar/console/rcar_printf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. + * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -19,11 +19,22 @@ #define INDEX_TIMER_COUNT (4U) +#define RCAR_LOG_HEAD (('T' << 0) | ('L' << 8) | ('O' << 16) | ('G' << 24)) + +/* + * The log is initialized and used before BL31 xlat tables are initialized, + * therefore the log memory is a device memory at that point. Make sure the + * memory is correclty aligned and accessed only with up-to 32bit, aligned, + * writes. + */ +CASSERT((RCAR_BL31_LOG_BASE & 0x7) == 0, assert_bl31_log_base_unaligned); +CASSERT((RCAR_BL31_LOG_MAX & 0x7) == 0, assert_bl31_log_max_unaligned); + extern RCAR_INSTANTIATE_LOCK typedef struct log_head { - uint8_t head[4]; + uint32_t head; uint32_t index; uint32_t size; - uint8_t res[4]; + uint32_t res; } loghead_t; typedef struct log_map { @@ -66,15 +77,12 @@ int32_t rcar_set_log_data(int32_t c) int32_t rcar_log_init(void) { - - static const uint8_t const_header[] = "TLOG"; - logmap_t *t_log; + logmap_t *t_log = (logmap_t *)RCAR_BL31_LOG_BASE; + uint32_t *log_data = (uint32_t *)t_log->log_data; int16_t init_flag = 0; + int i; - t_log = (logmap_t *) RCAR_BL31_LOG_BASE; - if (memcmp - ((const void *)t_log->header.head, (const void *)const_header, - sizeof(t_log->header.head)) != 0) { + if (t_log->header.head != RCAR_LOG_HEAD) { /* * Log header is not "TLOG", then log area initialize */ @@ -87,11 +95,10 @@ int32_t rcar_log_init(void) init_flag = 1; } if (init_flag == 1) { - (void)memset((void *)t_log->log_data, 0, - (size_t) RCAR_BL31_LOG_MAX); - (void)memcpy((void *)t_log->header.head, - (const void *)const_header, - sizeof(t_log->header.head)); + for (i = 0; i < RCAR_BL31_LOG_MAX; i += 4) + *log_data++ = 0; + + t_log->header.head = RCAR_LOG_HEAD; t_log->header.index = 0U; t_log->header.size = 0U; } diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts index 8b9c281e2..f4805db69 100644 --- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts +++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts @@ -27,17 +27,14 @@ binary_size = <0x80000>; }; - chosen { - linux,initrd-start = <0>; - linux,initrd-end = <0>; - }; - hypervisor { compatible = "hafnium,hafnium"; vm1 { is_ffa_partition; debug_name = "cactus-primary"; load_address = <0x7000000>; + vcpu_count = <8>; + mem_size = <1048576>; }; vm2 { is_ffa_partition; @@ -74,11 +71,6 @@ CPU_1 }; - device-memory@0 { - device_type = "device-memory"; - reg = <0x0 0x0 0x6000000 0x0 0x8000000 0x78000000>; - }; - memory@6000000 { device_type = "memory"; reg = <0x0 0x6000000 0x2000000>; /* Trusted DRAM */ diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts index 266adfc2b..57d6792e1 100644 --- a/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts +++ b/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts @@ -27,11 +27,6 @@ binary_size = <0x80000>; }; - chosen { - linux,initrd-start = <0>; - linux,initrd-end = <0>; - }; - hypervisor { compatible = "hafnium,hafnium"; vm1 { @@ -39,6 +34,8 @@ debug_name = "op-tee"; load_address = <0x6280000>; smc_whitelist = <0xbe000000>; + vcpu_count = <8>; + mem_size = <1048576>; }; }; @@ -61,11 +58,6 @@ CPU_1 }; - device-memory@0 { - device_type = "device-memory"; - reg = <0x0 0x0 0x6000000 0x0 0x8000000 0x78000000>; - }; - memory@6000000 { device_type = "memory"; reg = <0x0 0x6000000 0x2000000>; /* Trusted DRAM */ diff --git a/fdts/optee_sp_manifest.dts b/plat/arm/board/fvp/fdts/optee_sp_manifest.dts index 02a5ef340..928d0d3bf 100644 --- a/fdts/optee_sp_manifest.dts +++ b/plat/arm/board/fvp/fdts/optee_sp_manifest.dts @@ -30,4 +30,20 @@ /* Boot protocol */ gp-register-num = <0x0>; + + device-regions { + compatible = "arm,ffa-manifest-device-regions"; + + uart1 { + base-address = <0x00000000 0x1c0a0000>; + pages-count = <1>; + attributes = <0x3>; /* read-write */ + }; + + gicd { + base-address = <0x00000000 0x2f000000>; + pages-count = <16>; + attributes = <0x3>; /* read-write */ + }; + }; }; diff --git a/plat/marvell/armada/a3k/common/a3700_common.mk b/plat/marvell/armada/a3k/common/a3700_common.mk index 5e2f8e299..e2022fac7 100644 --- a/plat/marvell/armada/a3k/common/a3700_common.mk +++ b/plat/marvell/armada/a3k/common/a3700_common.mk @@ -64,7 +64,7 @@ BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ $(PLAT_COMMON_BASE)/a3700_sip_svc.c \ $(MARVELL_DRV) -ifneq (${WTP},) +ifdef WTP DOIMAGEPATH := $(WTP) DOIMAGETOOL := $(DOIMAGEPATH)/wtptp/src/TBB_Linux/release/TBB_linux @@ -85,6 +85,9 @@ endif #MARVELL_SECURE_BOOT TIMBUILD := $(DOIMAGEPATH)/script/buildtim.sh TIM2IMG := $(DOIMAGEPATH)/script/tim2img.pl +TIMDDRTOOL := $(DOIMAGEPATH)/tim/ddr/ddr_tool + +$(TIMBUILD): $(TIMDDRTOOL) # WTMI_IMG is used to specify the customized RTOS image running over # Service CPU (CM3 processor). By the default, it points to a @@ -101,7 +104,7 @@ WTMI_SYSINIT_IMG := $(DOIMAGEPATH)/wtmi/sys_init/build/sys_init.bin # and sys-init image (WTMI_SYSINIT_IMG). WTMI_MULTI_IMG := $(DOIMAGEPATH)/wtmi/build/wtmi.bin -WTMI_ENC_IMG := $(DOIMAGEPATH)/wtmi/build/wtmi-enc.bin +WTMI_ENC_IMG := $(BUILD_PLAT)/wtmi-enc.bin BUILD_UART := uart-images SRCPATH := $(dir $(BL33)) @@ -120,15 +123,20 @@ TIMBLDUARTARGS := $(MARVELL_SECURE_BOOT) UART $(IMAGESPATH) $(DOIMAGEPATH) $(CL $(DDR_TOPOLOGY) 0 0 $(DOIMAGE_CFG) $(TIMNCFG) $(TIMNSIG) 0 DOIMAGE_FLAGS := -r $(DOIMAGE_CFG) -v -D -$(DOIMAGETOOL): +$(DOIMAGETOOL): FORCE $(if $(value CRYPTOPP_PATH),,$(error "Platform '${PLAT}' for WTP image tool requires CRYPTOPP_PATH. Please set CRYPTOPP_PATH to point to the right directory")) $(Q)$(MAKE) --no-print-directory -C $(CRYPTOPP_PATH) -f GNUmakefile $(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH)/wtptp/src/TBB_Linux -f TBB_linux.mak LIBDIR=$(CRYPTOPP_PATH) -mrvl_flash: ${BUILD_PLAT}/${BOOT_IMAGE} ${DOIMAGETOOL} - $(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for target '$@' requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory")) - ${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} WTMI_IMG=$(WTMI_IMG) MV_DDR_PATH=$(MV_DDR_PATH) - $(shell truncate -s %4 $(WTMI_IMG)) +$(WTMI_MULTI_IMG): FORCE + $(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH) WTMI_IMG=$(WTMI_IMG) WTMI + +$(TIMDDRTOOL): FORCE + $(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for ddr tool requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory")) + $(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH) MV_DDR_PATH=$(MV_DDR_PATH) mv_ddr + +.PHONY: mrvl_flash +mrvl_flash: ${BUILD_PLAT}/${BOOT_IMAGE} ${WTMI_MULTI_IMG} ${DOIMAGETOOL} ${TIMBUILD} @echo @echo "Building uart images" $(TIMBUILD) $(TIMBLDUARTARGS) @@ -157,8 +165,9 @@ ifeq ($(MARVELL_SECURE_BOOT),1) @echo -e "\n\t=======================================================\n"; @echo -e "\t Secure boot. Encrypting wtmi and boot-image \n"; @echo -e "\t=======================================================\n"; - @truncate -s %16 $(WTMI_MULTI_IMG) - @openssl enc -aes-256-cbc -e -in $(WTMI_MULTI_IMG) \ + @cp $(WTMI_MULTI_IMG) $(BUILD_PLAT)/wtmi-align.bin + @truncate -s %16 $(BUILD_PLAT)/wtmi-align.bin + @openssl enc -aes-256-cbc -e -in $(BUILD_PLAT)/wtmi-align.bin \ -out $(WTMI_ENC_IMG) \ -K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \ -iv `cat $(IMAGESPATH)/iv.txt` -p @@ -170,15 +179,34 @@ ifeq ($(MARVELL_SECURE_BOOT),1) endif $(DOIMAGETOOL) $(DOIMAGE_FLAGS) @if [ -e "$(TIMNCFG)" ]; then $(DOIMAGETOOL) -r $(TIMNCFG); fi - @if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then sed -i 's|$(WTMI_MULTI_IMG)|$(WTMI_ENC_IMG)|1;s|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1;' $(TIMNCFG); fi +ifeq ($(MARVELL_SECURE_BOOT),1) + @sed -i 's|$(WTMI_MULTI_IMG)|$(WTMI_ENC_IMG)|1;s|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1;' $(TIMNCFG) +endif $(TIM2IMG) $(TIM2IMGARGS) -o $(BUILD_PLAT)/$(FLASH_IMAGE) - @mv -t $(BUILD_PLAT) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG) $(WTMI_IMG) $(WTMI_SYSINIT_IMG) $(WTMI_MULTI_IMG) - @if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then mv -t $(BUILD_PLAT) $(WTMI_ENC_IMG) OtpHash.txt; fi + @mv -t $(BUILD_PLAT) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG) + @cp -t $(BUILD_PLAT) $(WTMI_IMG) $(WTMI_SYSINIT_IMG) $(WTMI_MULTI_IMG) +ifeq ($(MARVELL_SECURE_BOOT),1) + @mv -t $(BUILD_PLAT) OtpHash.txt +endif @find . -name "*.txt" | grep -E "CSK[[:alnum:]]_KeyHash.txt|Tim_msg.txt|TIMHash.txt" | xargs rm -f -else # ${WTP} +clean realclean distclean: mrvl_clean + +.PHONY: mrvl_clean +mrvl_clean: + -$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH) MV_DDR_PATH=$(MV_DDR_PATH) clean + -$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH)/wtptp/src/TBB_Linux -f TBB_linux.mak LIBDIR=$(CRYPTOPP_PATH) clean +ifdef CRYPTOPP_PATH + -$(Q)$(MAKE) --no-print-directory -C $(CRYPTOPP_PATH) -f GNUmakefile clean +endif +else # WTP + +.PHONY: mrvl_flash mrvl_flash: $(error "Platform '${PLAT}' for target '$@' requires WTP. Please set WTP to point to the right directory") -endif # ${WTP} +endif # WTP + +.PHONY: FORCE +FORCE:; diff --git a/plat/marvell/armada/a8k/common/a8k_common.mk b/plat/marvell/armada/a8k/common/a8k_common.mk index 58394a46f..cf1516a28 100644 --- a/plat/marvell/armada/a8k/common/a8k_common.mk +++ b/plat/marvell/armada/a8k/common/a8k_common.mk @@ -152,14 +152,20 @@ BLE_PATH ?= $(PLAT_COMMON_BASE)/ble include ${BLE_PATH}/ble.mk $(eval $(call MAKE_BL,e)) +clean realclean distclean: mrvl_clean + +.PHONY: mrvl_clean mrvl_clean: @echo " Doimage CLEAN" ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean -${DOIMAGETOOL}: mrvl_clean +${DOIMAGETOOL}: FORCE @$(DOIMAGE_LIBS_CHECK) ${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} +.PHONY: mrvl_flash mrvl_flash: ${BUILD_PLAT}/${BOOT_IMAGE} ${DOIMAGETOOL} ${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE} +.PHONY: FORCE +FORCE:; diff --git a/plat/marvell/armada/common/marvell_common.mk b/plat/marvell/armada/common/marvell_common.mk index 7f8dffa00..e5ee710a6 100644 --- a/plat/marvell/armada/common/marvell_common.mk +++ b/plat/marvell/armada/common/marvell_common.mk @@ -87,10 +87,12 @@ include $(MARVELL_PLAT_BASE)/common/mss/mss_common.mk endif $(BUILD_PLAT)/$(BOOT_IMAGE): $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(FIP_NAME) + $(if $(shell find $(BUILD_PLAT)/bl1.bin -type f -size +128k),$(error "Image '$(BUILD_PLAT)/bl1.bin' is bigger than 128kB")) @cp $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; } @truncate -s %128K $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; } @cat $(BUILD_PLAT)/$(FIP_NAME) >> $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; } @truncate -s %4 $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; } @echo "Built $@ successfully" +.PHONY: mrvl_bootimage mrvl_bootimage: $(BUILD_PLAT)/$(BOOT_IMAGE) diff --git a/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c b/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c new file mode 100644 index 000000000..fca69130a --- /dev/null +++ b/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020, 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 (GET_WACS_FSM(reg_rdata) == SWINF_FSM_IDLE) { + break; + } + retry--; + }; + + 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); +} diff --git a/plat/mediatek/mt8183/drivers/uart/uart.c b/plat/mediatek/common/drivers/uart/uart.c index 3c6a98036..b940eb339 100644 --- a/plat/mediatek/mt8183/drivers/uart/uart.c +++ b/plat/mediatek/common/drivers/uart/uart.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -9,7 +9,7 @@ static struct mt_uart uart_save_addr[DRV_SUPPORT_UART_PORTS]; -static const unsigned int uart_base_addr[DRV_SUPPORT_UART_PORTS] = { +static const uint32_t uart_base_addr[DRV_SUPPORT_UART_PORTS] = { UART0_BASE, UART1_BASE }; @@ -99,13 +99,14 @@ void mt_uart_save(void) void mt_console_uart_cg(int on) { - if (on) + if (on == 1) { mmio_write_32(UART_CLOCK_GATE_CLR, UART0_CLOCK_GATE_BIT); - else + } else { mmio_write_32(UART_CLOCK_GATE_SET, UART0_CLOCK_GATE_BIT); + } } -int mt_console_uart_cg_status(void) +uint32_t mt_console_uart_cg_status(void) { return mmio_read_32(UART_CLOCK_GATE_STA) & UART0_CLOCK_GATE_BIT; } diff --git a/plat/mediatek/mt8183/drivers/uart/uart.h b/plat/mediatek/mt8183/drivers/uart/uart.h index be04c3509..062ce3adc 100644 --- a/plat/mediatek/mt8183/drivers/uart/uart.h +++ b/plat/mediatek/mt8183/drivers/uart/uart.h @@ -95,6 +95,6 @@ struct mt_uart { void mt_uart_save(void); void mt_uart_restore(void); void mt_console_uart_cg(int on); -int mt_console_uart_cg_status(void); +uint32_t mt_console_uart_cg_status(void); #endif /* __UART_H__ */ diff --git a/plat/mediatek/mt8183/platform.mk b/plat/mediatek/mt8183/platform.mk index f290a4e6d..07da1afac 100644 --- a/plat/mediatek/mt8183/platform.mk +++ b/plat/mediatek/mt8183/platform.mk @@ -45,6 +45,7 @@ BL31_SOURCES += common/desc_image_load.c \ ${MTK_PLAT}/common/mtk_plat_common.c \ ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init.c \ ${MTK_PLAT}/common/drivers/rtc/rtc_common.c \ + ${MTK_PLAT}/common/drivers/uart/uart.c \ ${MTK_PLAT}/common/params_setup.c \ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \ ${MTK_PLAT_SOC}/aarch64/platform_common.c \ @@ -58,7 +59,6 @@ BL31_SOURCES += common/desc_image_load.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_pmic_wrap.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c \ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \ - ${MTK_PLAT_SOC}/drivers/uart/uart.c \ ${MTK_PLAT_SOC}/drivers/timer/mt_timer.c \ ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c \ ${MTK_PLAT_SOC}/plat_pm.c \ diff --git a/plat/mediatek/mt8192/bl31_plat_setup.c b/plat/mediatek/mt8192/bl31_plat_setup.c index 9a01bef65..32e124f1f 100644 --- a/plat/mediatek/mt8192/bl31_plat_setup.c +++ b/plat/mediatek/mt8192/bl31_plat_setup.c @@ -11,12 +11,15 @@ #include <common/bl_common.h> #include <common/debug.h> #include <common/desc_image_load.h> +#include <drivers/generic_delay_timer.h> #include <drivers/ti/uart/uart_16550.h> #include <lib/coreboot.h> /* Platform Includes */ #include <gpio/mtgpio.h> #include <mt_gic_v3.h> +#include <mt_timer.h> +#include <mtk_dcm.h> #include <plat_params.h> #include <plat_private.h> @@ -81,10 +84,18 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, ******************************************************************************/ void bl31_platform_setup(void) { + /* Set dcm on */ + if (!dcm_set_default()) { + ERROR("Failed to set default dcm on!!\n"); + } + /* Initialize the GIC driver, CPU and distributor interfaces */ mt_gic_driver_init(); mt_gic_init(); + plat_mt8192_gpio_init(); + mt_systimer_init(); + generic_delay_timer_init(); } /******************************************************************************* diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c new file mode 100644 index 000000000..dd8bf4eed --- /dev/null +++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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); + 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_set_default(void) +{ + dcm_armcore(true); + dcm_mcusys(true); + dcm_stall(true); + + return check_dcm_state(); +} diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h new file mode 100644 index 000000000..ee98d0e38 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MTK_DCM_H +#define MTK_DCM_H + +#include <stdbool.h> + +bool dcm_set_default(void); + +#endif /* #ifndef MTK_DCM_H */ diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c new file mode 100644 index 000000000..15a700c2b --- /dev/null +++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2020, 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 &= ((mmio_read_32(MP_ADB_DCM_CFG0) & + MP_CPUSYS_TOP_ADB_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG0_ON); + ret &= ((mmio_read_32(MP_ADB_DCM_CFG4) & + MP_CPUSYS_TOP_ADB_DCM_REG1_MASK) == + (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG1_ON); + ret &= ((mmio_read_32(MCUSYS_DCM_CFG0) & + MP_CPUSYS_TOP_ADB_DCM_REG2_MASK) == + (unsigned int) 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_ADB_DCM_CFG0, + MP_CPUSYS_TOP_ADB_DCM_REG0_MASK, + MP_CPUSYS_TOP_ADB_DCM_REG0_ON); + mmio_clrsetbits_32(MP_ADB_DCM_CFG4, + MP_CPUSYS_TOP_ADB_DCM_REG1_MASK, + MP_CPUSYS_TOP_ADB_DCM_REG1_ON); + mmio_clrsetbits_32(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_ADB_DCM_CFG0, + MP_CPUSYS_TOP_ADB_DCM_REG0_MASK, + MP_CPUSYS_TOP_ADB_DCM_REG0_OFF); + mmio_clrsetbits_32(MP_ADB_DCM_CFG4, + MP_CPUSYS_TOP_ADB_DCM_REG1_MASK, + MP_CPUSYS_TOP_ADB_DCM_REG1_OFF); + mmio_clrsetbits_32(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 &= ((mmio_read_32(MP_MISC_DCM_CFG0) & + MP_CPUSYS_TOP_APB_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG0_ON); + ret &= ((mmio_read_32(MCUSYS_DCM_CFG0) & + MP_CPUSYS_TOP_APB_DCM_REG1_MASK) == + (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG1_ON); + ret &= ((mmio_read_32(MP0_DCM_CFG0) & + MP_CPUSYS_TOP_APB_DCM_REG2_MASK) == + (unsigned int) 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_MISC_DCM_CFG0, + MP_CPUSYS_TOP_APB_DCM_REG0_MASK, + MP_CPUSYS_TOP_APB_DCM_REG0_ON); + mmio_clrsetbits_32(MCUSYS_DCM_CFG0, + MP_CPUSYS_TOP_APB_DCM_REG1_MASK, + MP_CPUSYS_TOP_APB_DCM_REG1_ON); + mmio_clrsetbits_32(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_MISC_DCM_CFG0, + MP_CPUSYS_TOP_APB_DCM_REG0_MASK, + MP_CPUSYS_TOP_APB_DCM_REG0_OFF); + mmio_clrsetbits_32(MCUSYS_DCM_CFG0, + MP_CPUSYS_TOP_APB_DCM_REG1_MASK, + MP_CPUSYS_TOP_APB_DCM_REG1_OFF); + mmio_clrsetbits_32(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)) +#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11)) +#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11)) + +bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void) +{ + bool ret = true; + + ret &= ((mmio_read_32(BUS_PLLDIV_CFG) & + MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON); + + return ret; +} + +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(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(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) +{ + bool ret = true; + + ret &= ((mmio_read_32(MP0_DCM_CFG7) & + MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON); + + return ret; +} + +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(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(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) +{ + bool ret = true; + + ret &= ((mmio_read_32(MCSI_DCM0) & + MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON); + + return ret; +} + +void dcm_mp_cpusys_top_cpubiu_dcm(bool on) +{ + if (on) { + /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */ + mmio_clrsetbits_32(MCSI_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(MCSI_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(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 11)) + +bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void) +{ + bool ret = true; + + ret &= ((mmio_read_32(CPU_PLLDIV_CFG0) & + MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON); + + return ret; +} + +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(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(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(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 11)) + +bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void) +{ + bool ret = true; + + ret &= ((mmio_read_32(CPU_PLLDIV_CFG1) & + MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON); + + return ret; +} + +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(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(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_CPU_PLL_DIV_2_DCM_REG0_MASK (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_OFF ((0x0 << 11)) + +bool dcm_mp_cpusys_top_cpu_pll_div_2_dcm_is_on(void) +{ + bool ret = true; + + ret &= ((mmio_read_32(CPU_PLLDIV_CFG2) & + MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON); + + return ret; +} + +void dcm_mp_cpusys_top_cpu_pll_div_2_dcm(bool on) +{ + if (on) { + /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_2_dcm'" */ + mmio_clrsetbits_32(CPU_PLLDIV_CFG2, + MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK, + MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON); + } else { + /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_2_dcm'" */ + mmio_clrsetbits_32(CPU_PLLDIV_CFG2, + MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK, + MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_OFF); + } +} + +#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_OFF ((0x0 << 11)) + +bool dcm_mp_cpusys_top_cpu_pll_div_3_dcm_is_on(void) +{ + bool ret = true; + + ret &= ((mmio_read_32(CPU_PLLDIV_CFG3) & + MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON); + + return ret; +} + +void dcm_mp_cpusys_top_cpu_pll_div_3_dcm(bool on) +{ + if (on) { + /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_3_dcm'" */ + mmio_clrsetbits_32(CPU_PLLDIV_CFG3, + MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK, + MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON); + } else { + /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_3_dcm'" */ + mmio_clrsetbits_32(CPU_PLLDIV_CFG3, + MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK, + MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_OFF); + } +} + +#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON (BIT(11)) +#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_OFF ((0x0 << 11)) + +bool dcm_mp_cpusys_top_cpu_pll_div_4_dcm_is_on(void) +{ + bool ret = true; + + ret &= ((mmio_read_32(CPU_PLLDIV_CFG4) & + MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON); + + return ret; +} + +void dcm_mp_cpusys_top_cpu_pll_div_4_dcm(bool on) +{ + if (on) { + /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_4_dcm'" */ + mmio_clrsetbits_32(CPU_PLLDIV_CFG4, + MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK, + MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON); + } else { + /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_4_dcm'" */ + mmio_clrsetbits_32(CPU_PLLDIV_CFG4, + MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK, + MP_CPUSYS_TOP_CPU_PLL_DIV_4_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) +{ + bool ret = true; + + ret &= ((mmio_read_32(MP0_DCM_CFG7) & + MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON); + + return ret; +} + +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(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(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 ((0x1U << 31)) +#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON ((0x1U << 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) +{ + bool ret = true; + + ret &= ((mmio_read_32(BUS_PLLDIV_CFG) & + MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON); + + return ret; +} + +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(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(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) +{ + bool ret = true; + + ret &= ((mmio_read_32(MP_MISC_DCM_CFG0) & + MP_CPUSYS_TOP_MISC_DCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_MISC_DCM_REG0_ON); + + return ret; +} + +void dcm_mp_cpusys_top_misc_dcm(bool on) +{ + if (on) { + /* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */ + mmio_clrsetbits_32(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_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 &= ((mmio_read_32(MP_MISC_DCM_CFG0) & + MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK) == + (unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG0_ON); + ret &= ((mmio_read_32(MP0_DCM_CFG0) & + MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK) == + (unsigned int) 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_MISC_DCM_CFG0, + MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK, + MP_CPUSYS_TOP_MP0_QDCM_REG0_ON); + mmio_clrsetbits_32(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_MISC_DCM_CFG0, + MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK, + MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF); + mmio_clrsetbits_32(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) +{ + bool ret = true; + + ret &= ((mmio_read_32(EMI_WFIFO) & + CPCCFG_REG_EMI_WFIFO_REG0_MASK) == + (unsigned int) CPCCFG_REG_EMI_WFIFO_REG0_ON); + + return ret; +} + +void dcm_cpccfg_reg_emi_wfifo(bool on) +{ + if (on) { + /* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */ + mmio_clrsetbits_32(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(EMI_WFIFO, + CPCCFG_REG_EMI_WFIFO_REG0_MASK, + CPCCFG_REG_EMI_WFIFO_REG0_OFF); + } +} + diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h new file mode 100644 index 000000000..1cf78345e --- /dev/null +++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020, 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 CPU_PLLDIV_CFG0 (MP_CPUSYS_TOP_BASE + 0x22a0) +#define CPU_PLLDIV_CFG1 (MP_CPUSYS_TOP_BASE + 0x22a4) +#define CPU_PLLDIV_CFG2 (MP_CPUSYS_TOP_BASE + 0x22a8) +#define CPU_PLLDIV_CFG3 (MP_CPUSYS_TOP_BASE + 0x22ac) +#define CPU_PLLDIV_CFG4 (MP_CPUSYS_TOP_BASE + 0x22b0) +#define BUS_PLLDIV_CFG (MP_CPUSYS_TOP_BASE + 0x22e0) +#define MCSI_DCM0 (MP_CPUSYS_TOP_BASE + 0x2440) +#define MP_ADB_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2500) +#define MP_ADB_DCM_CFG4 (MP_CPUSYS_TOP_BASE + 0x2510) +#define MP_MISC_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2518) +#define MCUSYS_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x25c0) +#define EMI_WFIFO (CPCCFG_REG_BASE + 0x100) +#define MP0_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x4880) +#define 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_cpu_pll_div_2_dcm_is_on(void); +void dcm_mp_cpusys_top_cpu_pll_div_2_dcm(bool on); +bool dcm_mp_cpusys_top_cpu_pll_div_3_dcm_is_on(void); +void dcm_mp_cpusys_top_cpu_pll_div_3_dcm(bool on); +bool dcm_mp_cpusys_top_cpu_pll_div_4_dcm_is_on(void); +void dcm_mp_cpusys_top_cpu_pll_div_4_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 diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c new file mode 100644 index 000000000..d6d4af742 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stdint.h> + +#include <arch_helpers.h> +#include <lib/psci/psci.h> +#include <lib/spinlock.h> + +#include <mt_cpu_pm_cpc.h> +#include <mt_mcdi.h> +#include <plat_mtk_lpm.h> +#include <plat_pm.h> + +DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1); + +static int plat_mt_lp_cpu_rc; + +static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state) +{ + return 0; +} + +static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state) +{ + mtk_cpc_core_on_hint_clr(cpu); + + if (IS_SYSTEM_SUSPEND_STATE(state)) { + mtk_cpc_time_sync(); + } + + return 0; +} + +static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state) +{ + return 0; +} + +static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state) +{ + /* clear DBGPRCR.CORENPDRQ to allow CPU power down */ + write_dbgprcr_el1(0ULL); + + return 0; +} + +static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state) +{ + return 0; +} + +static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state) +{ + return 0; +} + +static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state) +{ + if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) { + return -1; + } + + mtk_cpc_mcusys_off_reflect(); + + return 0; +} + +static int pwr_mcusys_pwron_finished(unsigned int cpu, + const psci_power_state_t *state) +{ + if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) { + return -1; + } + + return 0; +} + +static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state) +{ + if (!IS_MCUSYS_OFF_STATE(state)) { + goto mt_pwr_mcusysoff_break; + } + + if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */ + goto mt_pwr_mcusysoff_break; + } + + return 0; + +mt_pwr_mcusysoff_break: + + plat_mt_lp_cpu_rc = -1; + + return -1; +} + +static const struct mt_lpm_tz plat_pm = { + .pwr_prompt = pwr_state_prompt, + .pwr_reflect = pwr_state_reflect, + .pwr_cpu_on = pwr_cpu_pwron, + .pwr_cpu_dwn = pwr_cpu_pwrdwn, + .pwr_cluster_on = pwr_cluster_pwron, + .pwr_cluster_dwn = pwr_cluster_pwrdwn, + .pwr_mcusys_dwn = pwr_mcusys_pwrdwn, + .pwr_mcusys_on = pwr_mcusys_pwron, + .pwr_mcusys_on_finished = pwr_mcusys_pwron_finished +}; + +const struct mt_lpm_tz *mt_plat_cpu_pm_init(void) +{ + mtk_cpc_init(); + + if (mcdi_try_init() == 0) { + INFO("MCDI init done.\n"); + } + + return &plat_pm; +} diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c new file mode 100644 index 000000000..f8c51a199 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <string.h> + +#include <drivers/delay_timer.h> + +#include <mt_cpu_pm_cpc.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(uint32_t prot_req, + uint32_t resp_reg, uint32_t resp_ofs) +{ + uint32_t sta, retry; + + retry = 0U; + + while (retry++ < RETRY_CNT_MAX) { + + mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req); + + udelay(1U); + + sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK; + + if (sta == PROT_SUCCESS) { + return CPC_SUCCESS; + } else if (sta == PROT_GIVEUP) { + return CPC_ERR_FAIL; + } + } + + return CPC_ERR_TIMEOUT; +} + +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); +} + +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(unsigned int cluster) +{ + 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(unsigned int cluster) +{ + mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR); +} + +static void mtk_cpc_cluster_cnt_backup(void) +{ + uint32_t backup_cnt; + uint32_t curr_cnt; + uint32_t cnt_mask = GENMASK(14, 0); + uint32_t clr_mask = GENMASK(1, 0); + + /* Single Cluster */ + backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP); + curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER); + + /* Get off count if dormant count is 0 */ + if ((curr_cnt & cnt_mask) == 0U) { + curr_cnt = (curr_cnt >> 16) & cnt_mask; + } else { + curr_cnt = curr_cnt & cnt_mask; + } + + mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt); + mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask); +} + +static inline void mtk_cpc_mcusys_off_en(void) +{ + mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U); +} + +static inline void mtk_cpc_mcusys_off_dis(void) +{ + mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U); +} + +void mtk_cpc_mcusys_off_reflect(void) +{ + mtk_cpc_mcusys_off_dis(); + 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_en(); + + return CPC_SUCCESS; +} + +void mtk_cpc_core_on_hint_set(unsigned int cpu) +{ + mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu)); +} + +void mtk_cpc_core_on_hint_clr(unsigned int cpu) +{ + mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu)); +} + +static void mtk_cpc_dump_timestamp(void) +{ + uint32_t id; + + for (id = 0U; 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(uint32_t cfg, uint32_t data) +{ + uint32_t val; + uint32_t reg = 0U; + + switch (cfg) { + case CPC_SMC_CONFIG_PROF: + reg = CPC_MCUSYS_CPC_DBG_SETTING; + val = mmio_read_32(reg); + val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN); + break; + case CPC_SMC_CONFIG_AUTO_OFF: + reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG; + val = mmio_read_32(reg); + if (data != 0U) { + val |= CPC_AUTO_OFF_EN; + cpc.auto_off = 1; + } else { + val &= ~CPC_AUTO_OFF_EN; + cpc.auto_off = 0; + } + break; + case CPC_SMC_CONFIG_AUTO_OFF_THRES: + reg = CPC_MCUSYS_CPC_OFF_THRES; + cpc.auto_thres_tick = us_to_ticks(data); + val = cpc.auto_thres_tick; + break; + case CPC_SMC_CONFIG_CNT_CLR: + reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR; + val = GENMASK(1, 0); /* clr_mask */ + break; + case CPC_SMC_CONFIG_TIME_SYNC: + mtk_cpc_time_sync(); + break; + default: + break; + } + + if (reg != 0U) { + mmio_write_32(reg, val); + } +} + +static uint32_t mtk_cpc_read_config(uint32_t cfg) +{ + uint32_t res = 0U; + + switch (cfg) { + case CPC_SMC_CONFIG_PROF: + res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ? + 1U : 0U; + 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: + break; + default: + break; + } + + return res; +} + +uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2) +{ + uint64_t res = 0ULL; + + switch (act) { + case CPC_SMC_EVENT_DUMP_TRACE_DATA: + mtk_cpc_dump_timestamp(); + break; + case CPC_SMC_EVENT_GIC_DPG_SET: + /* isolated_status = x2; */ + break; + case CPC_SMC_EVENT_CPC_CONFIG: + mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2); + break; + case CPC_SMC_EVENT_READ_CONFIG: + res = mtk_cpc_read_config((uint32_t)arg1); + break; + default: + break; + } + + return res; +} + +void mtk_cpc_init(void) +{ + mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING, + mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) + | CPC_DBG_EN + | CPC_CALC_EN); + + cpc.auto_off = 1; + cpc.auto_thres_tick = us_to_ticks(8000); + + mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, + mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG) + | CPC_OFF_PRE_EN + | (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U)); + + mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick); +} diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h new file mode 100644 index 000000000..19dd6a283 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020, 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 <lib/utils_def.h> +#include <mcucfg.h> +#include <platform_def.h> + +#define NEED_CPUSYS_PROT_WORKAROUND 1 + +/* system sram registers */ +#define CPUIDLE_SRAM_REG(r) (uint32_t)(MTK_MCDI_SRAM_BASE + (r)) + +/* db dump */ +#define CPC_TRACE_SIZE U(0x20) +#define CPC_TRACE_ID_NUM U(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 U(0x3) +#define CPUSYS_RESP_OFS U(16) +#define MCUSYS_RESP_OFS U(30) + +#define cpusys_resp(r) (((r) >> CPUSYS_RESP_OFS) & CPC_PROT_RESP_MASK) +#define mcusys_resp(r) (((r) >> MCUSYS_RESP_OFS) & CPC_PROT_RESP_MASK) + +#define RETRY_CNT_MAX U(1000) + +#define PROT_RETRY U(0) +#define PROT_SUCCESS U(1) +#define PROT_GIVEUP U(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 { + CPC_SUCCESS = 0, + + CPC_ERR_FAIL, + CPC_ERR_TIMEOUT, + + NF_CPC_ERR +}; + +enum { + 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 { + 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(unsigned int cluster); +void mtk_cpu_pm_cluster_prot_release(unsigned int cluster); + +void mtk_cpc_mcusys_off_reflect(void); +int mtk_cpc_mcusys_off_prepare(void); + +void mtk_cpc_core_on_hint_set(unsigned int cpu); +void mtk_cpc_core_on_hint_clr(unsigned int cpu); +void mtk_cpc_time_sync(void); + +uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2); +void mtk_cpc_init(void); + +#endif /* MT_CPU_PM_CPC_H */ diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c new file mode 100644 index 000000000..df741221d --- /dev/null +++ b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <cdefs.h> + +#include <lib/mmio.h> +#include <lib/utils_def.h> +#include <mt_mcdi.h> + +/* Read/Write */ +#define APMCU_MCUPM_MBOX_AP_READY U(0) +#define APMCU_MCUPM_MBOX_RESERVED_1 U(1) +#define APMCU_MCUPM_MBOX_RESERVED_2 U(2) +#define APMCU_MCUPM_MBOX_RESERVED_3 U(3) +#define APMCU_MCUPM_MBOX_PWR_CTRL_EN U(4) +#define APMCU_MCUPM_MBOX_L3_CACHE_MODE U(5) +#define APMCU_MCUPM_MBOX_BUCK_MODE U(6) +#define APMCU_MCUPM_MBOX_ARMPLL_MODE U(7) +/* Read only */ +#define APMCU_MCUPM_MBOX_TASK_STA U(8) +#define APMCU_MCUPM_MBOX_RESERVED_9 U(9) +#define APMCU_MCUPM_MBOX_RESERVED_10 U(10) +#define APMCU_MCUPM_MBOX_RESERVED_11 U(11) + +/* CPC mode - Read/Write */ +#define APMCU_MCUPM_MBOX_WAKEUP_CPU U(12) + +/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */ +#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 GENMASK(3, 0) + +/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */ +#define MCUPM_BUCK_NORMAL_MODE U(0) /* default */ +#define MCUPM_BUCK_LP_MODE U(1) +#define MCUPM_BUCK_OFF_MODE U(2) +#define NF_MCUPM_BUCK_MODE U(3) + +/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */ +#define MCUPM_ARMPLL_ON U(0) /* default */ +#define MCUPM_ARMPLL_GATING U(1) +#define MCUPM_ARMPLL_OFF U(2) +#define NF_MCUPM_ARMPLL_MODE U(3) + +/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */ +#define MCUPM_TASK_UNINIT U(0) +#define MCUPM_TASK_INIT U(1) +#define MCUPM_TASK_INIT_FINISH U(2) +#define MCUPM_TASK_WAIT U(3) +#define MCUPM_TASK_RUN U(4) +#define MCUPM_TASK_PAUSE U(5) + +#define SSPM_MBOX_3_BASE U(0x0c55fce0) + +#define MCDI_NOT_INIT 0 +#define MCDI_INIT_1 1 +#define MCDI_INIT_2 2 +#define MCDI_INIT_DONE 3 + +static int mcdi_init_status __section("tzfw_coherent_mem"); + +static inline uint32_t mcdi_mbox_read(uint32_t id) +{ + return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2)); +} + +static inline void mcdi_mbox_write(uint32_t id, uint32_t val) +{ + mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val); +} + +static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev) +{ + mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev); +} + +static void mtk_set_mcupm_pll_mode(uint32_t mode) +{ + if (mode < NF_MCUPM_ARMPLL_MODE) { + mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode); + } +} + +static void mtk_set_mcupm_buck_mode(uint32_t mode) +{ + if (mode < NF_MCUPM_BUCK_MODE) { + mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode); + } +} + +static int mtk_mcupm_is_ready(void) +{ + unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA); + + return (sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH); +} + +static int mcdi_init_1(void) +{ + unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA); + + if (sta != MCUPM_TASK_INIT) { + return -1; + } + + mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF); + mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE); + + mtk_mcupm_pwr_ctrl_setting( + MCUPM_MCUSYS_CTRL | + MCUPM_BUCK_CTRL | + MCUPM_ARMPLL_CTRL); + + mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1); + + return 0; +} + +static int mcdi_init_2(void) +{ + return mtk_mcupm_is_ready() ? 0 : -1; +} + +int mcdi_try_init(void) +{ + if (mcdi_init_status == MCDI_INIT_DONE) { + return 0; + } + + if (mcdi_init_status == MCDI_NOT_INIT) { + mcdi_init_status = MCDI_INIT_1; + } + + if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) { + mcdi_init_status = MCDI_INIT_2; + } + + if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) { + mcdi_init_status = MCDI_INIT_DONE; + } + + return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status; +} diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h new file mode 100644 index 000000000..f3545aabf --- /dev/null +++ b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MT_MCDI_H +#define MT_MCDI_H + +int mcdi_try_init(void); + +#endif /* MT_MCDI_H */ diff --git a/plat/mediatek/mt8192/drivers/pmic/pmic.c b/plat/mediatek/mt8192/drivers/pmic/pmic.c new file mode 100644 index 000000000..cca441397 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/pmic/pmic.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020, 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); +} diff --git a/plat/mediatek/mt8192/drivers/pmic/pmic.h b/plat/mediatek/mt8192/drivers/pmic/pmic.h new file mode 100644 index 000000000..aac22afa3 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/pmic/pmic.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020, 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 */ diff --git a/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h new file mode 100644 index 000000000..ae892ed5a --- /dev/null +++ b/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, 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" + +/* external API */ +int32_t pwrap_read(uint32_t adr, uint32_t *rdata); +int32_t pwrap_write(uint32_t adr, uint32_t wdata); + +static struct mt8192_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE; + +/* PMIC_WRAP registers */ +struct mt8192_pmic_wrap_regs { + uint32_t init_done; + uint32_t reserved[799]; + 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; +}; + +#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_H */ diff --git a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h new file mode 100644 index 000000000..92c71bcdd --- /dev/null +++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MTK_PTP3_H +#define MTK_PTP3_H + +#include <lib/mmio.h> +#include <lib/utils_def.h> + +/************************************************ + * BIT Operation and REG r/w + ************************************************/ +#define ptp3_read(addr) mmio_read_32((uintptr_t)addr) +#define ptp3_write(addr, val) mmio_write_32((uintptr_t)addr, val) + +/************************************************ + * CPU info + ************************************************/ +#define NR_PTP3_CFG1_CPU U(8) +#define PTP3_CFG1_CPU_START_ID U(0) +#define PTP3_CFG1_MASK 0x00100000 + +#define NR_PTP3_CFG2_CPU U(4) +#define PTP3_CFG2_CPU_START_ID U(4) + +#define NR_PTP3_CFG3_CPU U(4) +#define PTP3_CFG3_CPU_START_ID U(4) + +/************************************************ + * config enum + ************************************************/ +enum PTP3_CFG { + PTP3_CFG_ADDR, + PTP3_CFG_VALUE, + NR_PTP3_CFG, +}; + +/************************************ + * prototype + ************************************/ +/* init trigger for ptp3 feature */ +extern void ptp3_init(unsigned int core); +extern void ptp3_deinit(unsigned int core); + +#endif /* MTK_PTP3_H */ diff --git a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c new file mode 100644 index 000000000..053d21081 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. \ + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "mtk_ptp3_common.h" + +/************************************************ + * Central control: turn on sysPi protection + ************************************************/ +static unsigned int ptp3_cfg1[NR_PTP3_CFG1_CPU][NR_PTP3_CFG] = { + {0x0C530610, 0x110842}, + {0x0C530E10, 0x110842}, + {0x0C531610, 0x110842}, + {0x0C531E10, 0x110842}, + {0x0C532610, 0x110842}, + {0x0C532E10, 0x110842}, + {0x0C533610, 0x110842}, + {0x0C533E10, 0x110842} +}; +static unsigned int ptp3_cfg2[NR_PTP3_CFG2_CPU][NR_PTP3_CFG] = { + {0x0C53B830, 0x68000}, + {0x0C53BA30, 0x68000}, + {0x0C53BC30, 0x68000}, + {0x0C53BE30, 0x68000} +}; +static unsigned int ptp3_cfg3[NR_PTP3_CFG3_CPU][NR_PTP3_CFG] = { + {0x0C532480, 0x7C607C6}, + {0x0C532C80, 0x7C607C6}, + {0x0C533480, 0x7C607C6}, + {0x0C533C80, 0x7C607C6} +}; + +/************************************************ + * API + ************************************************/ +void ptp3_init(unsigned int core) +{ + unsigned int _core; + + if (core >= PTP3_CFG1_CPU_START_ID) { + if (core < NR_PTP3_CFG1_CPU) { + /* update ptp3_cfg1 */ + ptp3_write( + ptp3_cfg1[core][PTP3_CFG_ADDR], + ptp3_cfg1[core][PTP3_CFG_VALUE]); + } + } + + if (core >= PTP3_CFG2_CPU_START_ID) { + _core = core - PTP3_CFG2_CPU_START_ID; + + if (_core < NR_PTP3_CFG2_CPU) { + /* update ptp3_cfg2 */ + ptp3_write( + ptp3_cfg2[_core][PTP3_CFG_ADDR], + ptp3_cfg2[_core][PTP3_CFG_VALUE]); + } + } + + if (core >= PTP3_CFG3_CPU_START_ID) { + _core = core - PTP3_CFG3_CPU_START_ID; + + if (_core < NR_PTP3_CFG3_CPU) { + /* update ptp3_cfg3 */ + ptp3_write( + ptp3_cfg3[_core][PTP3_CFG_ADDR], + ptp3_cfg3[_core][PTP3_CFG_VALUE]); + } + } +} + +void ptp3_deinit(unsigned int core) +{ + if (core >= PTP3_CFG1_CPU_START_ID) { + if (core < NR_PTP3_CFG1_CPU) { + /* update ptp3_cfg1 */ + ptp3_write( + ptp3_cfg1[core][PTP3_CFG_ADDR], + ptp3_cfg1[core][PTP3_CFG_VALUE] & + ~PTP3_CFG1_MASK); + } + } +} diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc.c b/plat/mediatek/mt8192/drivers/spmc/mtspmc.c new file mode 100644 index 000000000..7ccebd6ab --- /dev/null +++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <mcucfg.h> +#include <mtspmc.h> +#include <mtspmc_private.h> + + +void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu) +{ + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu)); +} + +void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu) +{ + mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu)); +} + +void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr) +{ + assert(cluster == 0U); + + mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr); +} + +uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu) +{ + assert(cluster == 0U); + + return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR)); +} + +void mcucfg_init_archstate(uint32_t cluster, uint32_t cpu, bool arm64) +{ + uint32_t reg; + + assert(cluster == 0U); + + reg = per_cluster(cluster, MCUCFG_INITARCH); + + if (arm64) { + mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu)); + } else { + mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu)); + } +} + +/** + * Return subsystem's power state. + * + * @mask: mask to SPM_CPU_PWR_STATUS to query the power state + * of one subsystem. + * RETURNS: + * 0 (the subsys was powered off) + * 1 (the subsys was powered on) + */ +bool spm_get_powerstate(uint32_t mask) +{ + return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask) != 0U; +} + +bool spm_get_cluster_powerstate(uint32_t cluster) +{ + assert(cluster == 0U); + + return spm_get_powerstate(MP0_CPUTOP); +} + +bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu) +{ + uint32_t mask = BIT(cpu); + + assert(cluster == 0U); + + return spm_get_powerstate(mask); +} + +int spmc_init(void) +{ + INFO("SPM: enable CPC mode\n"); + + mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN); + + mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B); + mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B); + mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B); + mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B); + mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B); + mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B); + mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B); + + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(1)); + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(2)); + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(3)); + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(4)); + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(5)); + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(6)); + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(7)); + + mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG); + mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG); + mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG); + + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE); + + return 0; +} + +/** + * Power on a core with specified cluster and core index + * + * @cluster: the cluster ID of the CPU which to be powered on + * @cpu: the CPU ID of the CPU which to be powered on + */ +void spm_poweron_cpu(uint32_t cluster, uint32_t cpu) +{ + /* set to 0 after BIG VPROC bulk on & before B-core power on seq. */ + if (cpu >= 4U) { + mmio_write_32(DREQ20_BIG_VPROC_ISO, 0U); + } + + mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN); + mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON); + + while (!spm_get_cpu_powerstate(cluster, cpu)) { + } + + mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN); + + /* Enable Big CPU Last PC */ + if (cpu >= 4U) { + mmio_clrbits_32(LAST_PC_REG(cpu), BIT(3)); + } +} + +/** + * Power off a core with specified cluster and core index + * + * @cluster: the cluster ID of the CPU which to be powered off + * @cpu: the CPU ID of the CPU which to be powered off + */ +void spm_poweroff_cpu(uint32_t cluster, uint32_t cpu) +{ + /* Set mp0_spmc_pwr_on_cpuX = 0 */ + mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON); +} + +/** + * Power off a cluster with specified index + * + * @cluster: the cluster index which to be powered off + */ +void spm_poweroff_cluster(uint32_t cluster) +{ + /* No need to power on/off cluster on single cluster platform */ + assert(false); +} + +/** + * Power on a cluster with specified index + * + * @cluster: the cluster index which to be powered on + */ +void spm_poweron_cluster(uint32_t cluster) +{ + /* No need to power on/off cluster on single cluster platform */ + assert(false); +} diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc.h b/plat/mediatek/mt8192/drivers/spmc/mtspmc.h new file mode 100644 index 000000000..7ed2e6220 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MTSPMC_H +#define MTSPMC_H + +#include <stdint.h> + +int spmc_init(void); + +void spm_poweron_cpu(uint32_t cluster, uint32_t cpu); +void spm_poweroff_cpu(uint32_t cluster, uint32_t cpu); + +void spm_poweroff_cluster(uint32_t cluster); +void spm_poweron_cluster(uint32_t cluster); + +bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu); +bool spm_get_cluster_powerstate(uint32_t cluster); +bool spm_get_powerstate(uint32_t mask); + +void mcucfg_init_archstate(uint32_t cluster, uint32_t cpu, bool arm64); +void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr); +uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu); + +void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu); +void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu); + +#endif /* MTSPMC_H */ diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h new file mode 100644 index 000000000..ad782955d --- /dev/null +++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MTSPMC_PRIVATE_H +#define MTSPMC_PRIVATE_H + +#include <lib/utils_def.h> +#include <platform_def.h> + +unsigned long read_cpuectlr(void); +void write_cpuectlr(unsigned long cpuectlr); + +unsigned long read_cpupwrctlr_el1(void); +void write_cpupwrctlr_el1(unsigned long cpuectlr); + +/* + * per_cpu/cluster helper + */ +struct per_cpu_reg { + unsigned int cluster_addr; + unsigned int cpu_stride; +}; + +#define per_cpu(cluster, cpu, reg) \ + (reg[cluster].cluster_addr + (cpu << reg[cluster].cpu_stride)) + +#define per_cluster(cluster, reg) (reg[cluster].cluster_addr) + +#define SPM_REG(ofs) (uint32_t)(SPM_BASE + (ofs)) +#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs)) +#define INFRACFG_AO_REG(ofs) (uint32_t)(INFRACFG_AO_BASE + (ofs)) + +/* === SPMC related registers */ +#define SPM_POWERON_CONFIG_EN SPM_REG(0x000) +/* bit-fields of SPM_POWERON_CONFIG_EN */ +#define PROJECT_CODE (U(0xb16) << 16) +#define BCLK_CG_EN BIT(0) + +#define SPM_PWR_STATUS SPM_REG(0x16c) +#define SPM_PWR_STATUS_2ND SPM_REG(0x170) +#define SPM_CPU_PWR_STATUS SPM_REG(0x174) + +/* bit-fields of SPM_PWR_STATUS */ +#define MD BIT(0) +#define CONN BIT(1) +#define DDRPHY BIT(2) +#define DISP BIT(3) +#define MFG BIT(4) +#define ISP BIT(5) +#define INFRA BIT(6) +#define VDEC BIT(7) +#define MP0_CPUTOP BIT(8) +#define MP0_CPU0 BIT(9) +#define MP0_CPU1 BIT(10) +#define MP0_CPU2 BIT(11) +#define MP0_CPU3 BIT(12) +#define MCUSYS BIT(14) +#define MP0_CPU4 BIT(15) +#define MP0_CPU5 BIT(16) +#define MP0_CPU6 BIT(17) +#define MP0_CPU7 BIT(18) +#define VEN BIT(21) + +/* === SPMC related registers */ +#define SPM_MCUSYS_PWR_CON MCUCFG_REG(0xd200) +#define SPM_MP0_CPUTOP_PWR_CON MCUCFG_REG(0xd204) +#define SPM_MP0_CPU0_PWR_CON MCUCFG_REG(0xd208) +#define SPM_MP0_CPU1_PWR_CON MCUCFG_REG(0xd20c) +#define SPM_MP0_CPU2_PWR_CON MCUCFG_REG(0xd210) +#define SPM_MP0_CPU3_PWR_CON MCUCFG_REG(0xd214) +#define SPM_MP0_CPU4_PWR_CON MCUCFG_REG(0xd218) +#define SPM_MP0_CPU5_PWR_CON MCUCFG_REG(0xd21c) +#define SPM_MP0_CPU6_PWR_CON MCUCFG_REG(0xd220) +#define SPM_MP0_CPU7_PWR_CON MCUCFG_REG(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) + +/**** per_cpu registers for SPM_MP0_CPU?_PWR_CON */ +static const struct per_cpu_reg SPM_CPU_PWR[] = { + { .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2U } +}; + +/**** per_cluster registers for SPM_MP0_CPUTOP_PWR_CON */ +static const struct per_cpu_reg SPM_CLUSTER_PWR[] = { + { .cluster_addr = SPM_MP0_CPUTOP_PWR_CON, .cpu_stride = 0U } +}; + +/* === MCUCFG related registers */ +/* aa64naa32 */ +#define MCUCFG_MP0_CLUSTER_CFG5 MCUCFG_REG(0xc8e4) +/* reset vectors */ +#define MCUCFG_MP0_CLUSTER_CFG8 MCUCFG_REG(0xc900) +#define MCUCFG_MP0_CLUSTER_CFG10 MCUCFG_REG(0xc908) +#define MCUCFG_MP0_CLUSTER_CFG12 MCUCFG_REG(0xc910) +#define MCUCFG_MP0_CLUSTER_CFG14 MCUCFG_REG(0xc918) +#define MCUCFG_MP0_CLUSTER_CFG16 MCUCFG_REG(0xc920) +#define MCUCFG_MP0_CLUSTER_CFG18 MCUCFG_REG(0xc928) +#define MCUCFG_MP0_CLUSTER_CFG20 MCUCFG_REG(0xc930) +#define MCUCFG_MP0_CLUSTER_CFG22 MCUCFG_REG(0xc938) + +/* MCUSYS DREQ BIG VPROC ISO control */ +#define DREQ20_BIG_VPROC_ISO MCUCFG_REG(0xad8c) + +/**** per_cpu registers for MCUCFG_MP0_CLUSTER_CFG? */ +static const struct per_cpu_reg MCUCFG_BOOTADDR[] = { + { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG8, .cpu_stride = 3U } +}; + +/**** per_cpu registers for MCUCFG_MP0_CLUSTER_CFG5 */ +static const struct per_cpu_reg MCUCFG_INITARCH[] = { + { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG5, .cpu_stride = 0U } +}; + +#define MCUCFG_INITARCH_CPU_BIT(cpu) BIT(16U + cpu) +#define LAST_PC_REG(cpu) (MCUCFG_REG(0x308) + (cpu * 0x800)) + +/* === CPC control */ +#define MCUCFG_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814) +#define MCUCFG_CPC_SPMC_PWR_STATUS MCUCFG_REG(0xa840) + +/* bit fields of CPC_FLOW_CTRL_CFG */ +#define CPC_CTRL_ENABLE BIT(16) +#define SSPM_ALL_PWR_CTRL_EN BIT(13) /* for cpu-hotplug */ +#define GIC_WAKEUP_IGNORE(cpu) BIT(21 + cpu) + +/* bit fields of CPC_SPMC_PWR_STATUS */ +#define CORE_SPMC_PWR_ON_ACK GENMASK(15, 0) + +/* === APB Module infracfg_ao */ +#define INFRA_TOPAXI_PROTECTEN INFRACFG_AO_REG(0x0220) +#define INFRA_TOPAXI_PROTECTEN_STA0 INFRACFG_AO_REG(0x0224) +#define INFRA_TOPAXI_PROTECTEN_STA1 INFRACFG_AO_REG(0x0228) +#define INFRA_TOPAXI_PROTECTEN_SET INFRACFG_AO_REG(0x02a0) +#define INFRA_TOPAXI_PROTECTEN_CLR INFRACFG_AO_REG(0x02a4) +#define INFRA_TOPAXI_PROTECTEN_1 INFRACFG_AO_REG(0x0250) +#define INFRA_TOPAXI_PROTECTEN_STA0_1 INFRACFG_AO_REG(0x0254) +#define INFRA_TOPAXI_PROTECTEN_STA1_1 INFRACFG_AO_REG(0x0258) +#define INFRA_TOPAXI_PROTECTEN_1_SET INFRACFG_AO_REG(0x02a8) +#define INFRA_TOPAXI_PROTECTEN_1_CLR INFRACFG_AO_REG(0x02ac) + +/* bit fields of INFRA_TOPAXI_PROTECTEN */ +#define MP0_SPMC_PROT_STEP1_0_MASK BIT(12) +#define MP0_SPMC_PROT_STEP1_1_MASK (BIT(26) | BIT(12)) + +/* === SPARK */ +#define VOLTAGE_04 U(0x40) +#define VOLTAGE_05 U(0x60) + +#define PTP3_CPU0_SPMC_SW_CFG MCUCFG_REG(0x200) +#define CPU0_ILDO_CONTROL5 MCUCFG_REG(0x334) +#define CPU0_ILDO_CONTROL8 MCUCFG_REG(0x340) + +/* bit fields of CPU0_ILDO_CONTROL5 */ +#define ILDO_RET_VOSEL GENMASK(7, 0) + +/* bit fields of PTP3_CPU_SPMC_SW_CFG */ +#define SW_SPARK_EN BIT(0) + +/* bit fields of CPU0_ILDO_CONTROL8 */ +#define ILDO_BYPASS_B BIT(0) + +static const struct per_cpu_reg MCUCFG_SPARK[] = { + { .cluster_addr = PTP3_CPU0_SPMC_SW_CFG, .cpu_stride = 11U } +}; + +static const struct per_cpu_reg ILDO_CONTROL5[] = { + { .cluster_addr = CPU0_ILDO_CONTROL5, .cpu_stride = 11U } +}; + +static const struct per_cpu_reg ILDO_CONTROL8[] = { + { .cluster_addr = CPU0_ILDO_CONTROL8, .cpu_stride = 11U } +}; + +#endif /* MTSPMC_PRIVATE_H */ diff --git a/plat/mediatek/mt8192/drivers/timer/mt_timer.c b/plat/mediatek/mt8192/drivers/timer/mt_timer.c index 781f940b6..08608854a 100644 --- a/plat/mediatek/mt8192/drivers/timer/mt_timer.c +++ b/plat/mediatek/mt8192/drivers/timer/mt_timer.c @@ -5,6 +5,7 @@ */ #include <arch_helpers.h> +#include <lib/mmio.h> #include <mt_timer.h> #include <platform_def.h> @@ -28,3 +29,10 @@ uint64_t sched_clock(void) - normal_time_base; return cval; } + +void mt_systimer_init(void) +{ + /* 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); +} diff --git a/plat/mediatek/mt8192/drivers/timer/mt_timer.h b/plat/mediatek/mt8192/drivers/timer/mt_timer.h index 7aca4a3bf..b35317715 100644 --- a/plat/mediatek/mt8192/drivers/timer/mt_timer.h +++ b/plat/mediatek/mt8192/drivers/timer/mt_timer.h @@ -12,6 +12,8 @@ #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) @@ -23,8 +25,11 @@ #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); +void mt_systimer_init(void); #endif /* MT_TIMER_H */ diff --git a/plat/mediatek/mt8192/drivers/uart/uart.h b/plat/mediatek/mt8192/drivers/uart/uart.h new file mode 100644 index 000000000..ac8b94dd1 --- /dev/null +++ b/plat/mediatek/mt8192/drivers/uart/uart.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020, 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__ */ diff --git a/plat/mediatek/mt8192/include/mcucfg.h b/plat/mediatek/mt8192/include/mcucfg.h new file mode 100644 index 000000000..046cf7314 --- /dev/null +++ b/plat/mediatek/mt8192/include/mcucfg.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MCUCFG_H +#define MCUCFG_H + +#ifndef __ASSEMBLER__ +#include <stdint.h> +#endif /* __ASSEMBLER__ */ + +#include <platform_def.h> + +#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs)) + +#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_REG(0x2290) + ((cpu) * 8)) +#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_REG(0x2294) + ((cpu) * 8)) + +#define MP2_CPUCFG MCUCFG_REG(0x2208) + +#define MP2_CPU0_STANDBYWFE BIT(4) +#define MP2_CPU1_STANDBYWFE BIT(5) + +#define MP0_CPUTOP_SPMC_CTL MCUCFG_REG(0x788) +#define MP1_CPUTOP_SPMC_CTL MCUCFG_REG(0x78C) +#define MP1_CPUTOP_SPMC_SRAM_CTL MCUCFG_REG(0x790) + +#define sw_spark_en BIT(0) +#define sw_no_wait_for_q_channel BIT(1) +#define sw_fsm_override BIT(2) +#define sw_logic_pre1_pdb BIT(3) +#define sw_logic_pre2_pdb BIT(4) +#define sw_logic_pdb BIT(5) +#define sw_iso BIT(6) +#define sw_sram_sleepb (U(0x3F) << 7) +#define sw_sram_isointb BIT(13) +#define sw_clk_dis BIT(14) +#define sw_ckiso BIT(15) +#define sw_pd (U(0x3F) << 16) +#define sw_hot_plug_reset BIT(22) +#define sw_pwr_on_override_en BIT(23) +#define sw_pwr_on BIT(24) +#define sw_coq_dis BIT(25) +#define logic_pdbo_all_off_ack BIT(26) +#define logic_pdbo_all_on_ack BIT(27) +#define logic_pre2_pdbo_all_on_ack BIT(28) +#define logic_pre1_pdbo_all_on_ack BIT(29) + + +#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) \ + (MCUCFG_REG(0x1c30) + cluster * 0x2000 + cpu * 4) + +#define CPUSYS0_CPU0_SPMC_CTL MCUCFG_REG(0x1c30) +#define CPUSYS0_CPU1_SPMC_CTL MCUCFG_REG(0x1c34) +#define CPUSYS0_CPU2_SPMC_CTL MCUCFG_REG(0x1c38) +#define CPUSYS0_CPU3_SPMC_CTL MCUCFG_REG(0x1c3C) + +#define CPUSYS1_CPU0_SPMC_CTL MCUCFG_REG(0x3c30) +#define CPUSYS1_CPU1_SPMC_CTL MCUCFG_REG(0x3c34) +#define CPUSYS1_CPU2_SPMC_CTL MCUCFG_REG(0x3c38) +#define CPUSYS1_CPU3_SPMC_CTL MCUCFG_REG(0x3c3C) + +#define cpu_sw_spark_en BIT(0) +#define cpu_sw_no_wait_for_q_channel BIT(1) +#define cpu_sw_fsm_override BIT(2) +#define cpu_sw_logic_pre1_pdb BIT(3) +#define cpu_sw_logic_pre2_pdb BIT(4) +#define cpu_sw_logic_pdb BIT(5) +#define cpu_sw_iso BIT(6) +#define cpu_sw_sram_sleepb BIT(7) +#define cpu_sw_sram_isointb BIT(8) +#define cpu_sw_clk_dis BIT(9) +#define cpu_sw_ckiso BIT(10) +#define cpu_sw_pd (U(0x1F) << 11) +#define cpu_sw_hot_plug_reset BIT(16) +#define cpu_sw_powr_on_override_en BIT(17) +#define cpu_sw_pwr_on BIT(18) +#define cpu_spark2ldo_allswoff BIT(19) +#define cpu_pdbo_all_on_ack BIT(20) +#define cpu_pre2_pdbo_allon_ack BIT(21) +#define cpu_pre1_pdbo_allon_ack BIT(22) + +/* CPC related registers */ +#define CPC_MCUSYS_CPC_OFF_THRES MCUCFG_REG(0xa714) +#define CPC_MCUSYS_PWR_CTRL MCUCFG_REG(0xa804) +#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814) +#define CPC_MCUSYS_LAST_CORE_REQ MCUCFG_REG(0xa818) +#define CPC_MCUSYS_MP_LAST_CORE_RESP MCUCFG_REG(0xa81c) +#define CPC_MCUSYS_LAST_CORE_RESP MCUCFG_REG(0xa824) +#define CPC_MCUSYS_PWR_ON_MASK MCUCFG_REG(0xa828) +#define CPC_MCUSYS_CPU_ON_SW_HINT_SET MCUCFG_REG(0xa8a8) +#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR MCUCFG_REG(0xa8ac) +#define CPC_MCUSYS_CPC_DBG_SETTING MCUCFG_REG(0xab00) +#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE MCUCFG_REG(0xab04) +#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE MCUCFG_REG(0xab08) +#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE MCUCFG_REG(0xab0c) +#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE MCUCFG_REG(0xab10) +#define CPC_MCUSYS_TRACE_SEL MCUCFG_REG(0xab14) +#define CPC_MCUSYS_TRACE_DATA MCUCFG_REG(0xab20) +#define CPC_MCUSYS_CLUSTER_COUNTER MCUCFG_REG(0xab70) +#define CPC_MCUSYS_CLUSTER_COUNTER_CLR MCUCFG_REG(0xab74) + +#define SPARK2LDO MCUCFG_REG(0x2700) +/* APB Module mcucfg */ +#define MP0_CA7_CACHE_CONFIG MCUCFG_REG(0x000) +#define MP0_AXI_CONFIG MCUCFG_REG(0x02C) +#define MP0_MISC_CONFIG0 MCUCFG_REG(0x030) +#define MP0_MISC_CONFIG1 MCUCFG_REG(0x034) +#define MP0_MISC_CONFIG2 MCUCFG_REG(0x038) +#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MP0_MISC_CONFIG2 + ((cpu) * 8)) +#define MP0_MISC_CONFIG3 MCUCFG_REG(0x03C) +#define MP0_MISC_CONFIG9 MCUCFG_REG(0x054) +#define MP0_CA7_MISC_CONFIG MCUCFG_REG(0x064) + +#define MP0_RW_RSVD0 MCUCFG_REG(0x06C) + + +#define MP1_CA7_CACHE_CONFIG MCUCFG_REG(0x200) +#define MP1_AXI_CONFIG MCUCFG_REG(0x22C) +#define MP1_MISC_CONFIG0 MCUCFG_REG(0x230) +#define MP1_MISC_CONFIG1 MCUCFG_REG(0x234) +#define MP1_MISC_CONFIG2 MCUCFG_REG(0x238) +#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MP1_MISC_CONFIG2 + ((cpu) * 8)) +#define MP1_MISC_CONFIG3 MCUCFG_REG(0x23C) +#define MP1_MISC_CONFIG9 MCUCFG_REG(0x254) +#define MP1_CA7_MISC_CONFIG MCUCFG_REG(0x264) + +#define CCI_ADB400_DCM_CONFIG MCUCFG_REG(0x740) +#define SYNC_DCM_CONFIG MCUCFG_REG(0x744) + +#define MP0_CLUSTER_CFG0 MCUCFG_REG(0xC8D0) + +#define MP0_SPMC MCUCFG_REG(0x788) +#define MP1_SPMC MCUCFG_REG(0x78C) +#define MP2_AXI_CONFIG MCUCFG_REG(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_REG(0x1c00) +#define CPUSYS0_SPARKEN MCUCFG_REG(0x1c04) +#define CPUSYS0_AMUXSEL MCUCFG_REG(0x1c08) +#define CPUSYS1_SPARKVRETCNTRL MCUCFG_REG(0x3c00) +#define CPUSYS1_SPARKEN MCUCFG_REG(0x3c04) +#define CPUSYS1_AMUXSEL MCUCFG_REG(0x3c08) + +#define MP2_PWR_RST_CTL MCUCFG_REG(0x2008) +#define MP2_PTP3_CPUTOP_SPMC0 MCUCFG_REG(0x22A0) +#define MP2_PTP3_CPUTOP_SPMC1 MCUCFG_REG(0x22A4) + +#define MP2_COQ MCUCFG_REG(0x22BC) +#define MP2_COQ_SW_DIS BIT(0) + +#define MP2_CA15M_MON_SEL MCUCFG_REG(0x2400) +#define MP2_CA15M_MON_L MCUCFG_REG(0x2404) + +#define CPUSYS2_CPU0_SPMC_CTL MCUCFG_REG(0x2430) +#define CPUSYS2_CPU1_SPMC_CTL MCUCFG_REG(0x2438) +#define CPUSYS2_CPU0_SPMC_STA MCUCFG_REG(0x2434) +#define CPUSYS2_CPU1_SPMC_STA MCUCFG_REG(0x243C) + +#define MP0_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x068) +#define MP1_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x268) +#define BIG_DBG_PWR_CTRL MCUCFG_REG(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 18U +#define B_SW_PD (U(0x3f) << B_SW_PD_OFFSET) + +#define B_SW_SRAM_SLEEPB_OFFSET 12U +#define B_SW_SRAM_SLEEPB (U(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 (6U) +#define B_FSM_STATE_OUT_MASK (U(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_CPUCFG_64BIT_SHIFT = 12U, + MP1_CPUCFG_64BIT_SHIFT = 28U, + MP0_CPUCFG_64BIT = U(0xf) << MP0_CPUCFG_64BIT_SHIFT, + MP1_CPUCFG_64BIT = U(0xf) << MP1_CPUCFG_64BIT_SHIFT +}; + +enum { + MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0U, + MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4U, + MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8U, + MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12U, + MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16U, + + MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK = + U(0xf) << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT, + MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK = + U(0xf) << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT, + MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK = + U(0xf) << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT, + MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK = + U(0xf) << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT, + MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK = + U(0xf) << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT +}; + +enum { + MP1_AINACTS_SHIFT = 4U, + MP1_AINACTS = 1U << MP1_AINACTS_SHIFT +}; + +enum { + MP1_SW_CG_GEN_SHIFT = 12U, + MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT +}; + +enum { + MP1_L2RSTDISABLE_SHIFT = 14U, + MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT +}; +#endif /* __ASSEMBLER__ */ + +#endif /* MCUCFG_H */ diff --git a/plat/mediatek/mt8192/include/plat_mt_cirq.h b/plat/mediatek/mt8192/include/plat_mt_cirq.h index 581860109..bb8b4577f 100644 --- a/plat/mediatek/mt8192/include/plat_mt_cirq.h +++ b/plat/mediatek/mt8192/include/plat_mt_cirq.h @@ -7,24 +7,53 @@ #ifndef PLAT_MT_CIRQ_H #define PLAT_MT_CIRQ_H -#define SYS_CIRQ_BASE U(0x10204000) -#define CIRQ_IRQ_NUM U(439) -#define CIRQ_SPI_START U(96) +#include <stdint.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 U(0x000) -#define CIRQ_ACK_BASE U(0x080) -#define CIRQ_MASK_BASE U(0x100) -#define CIRQ_MASK_SET_BASE U(0x180) -#define CIRQ_MASK_CLR_BASE U(0x200) -#define CIRQ_SENS_BASE U(0x280) -#define CIRQ_SENS_SET_BASE U(0x300) -#define CIRQ_SENS_CLR_BASE U(0x380) -#define CIRQ_POL_BASE U(0x400) -#define CIRQ_POL_SET_BASE U(0x480) -#define CIRQ_POL_CLR_BASE U(0x500) -#define CIRQ_CON U(0x600) + +#define SYS_CIRQ_BASE U(0x10204000) +#define CIRQ_REG_NUM U(14) +#define CIRQ_IRQ_NUM U(439) +#define CIRQ_SPI_START U(64) +#define MD_WDT_IRQ_BIT_ID U(110) + +#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 @@ -32,8 +61,8 @@ #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_EVENT_BITS U(31) #define CIRQ_CON_SW_RST_BITS U(20) +#define CIRQ_CON_EVENT_BITS U(31) #define CIRQ_CON_BITS_MASK U(0x7) /* @@ -41,42 +70,59 @@ */ #define CIRQ_CON_EN U(0x1) #define CIRQ_CON_EDGE_ONLY U(0x1) -#define CIRQ_SW_RESET 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 MT_CIRQ_EDGE_SENSITIVE U(0) -#define MT_CIRQ_LEVEL_SENSITIVE U(1) -/* - * Define macro - */ -#define IRQ_TO_CIRQ_NUM(irq) ((irq) - (CIRQ_SPI_START)) -#define CIRQ_TO_IRQ_NUM(cirq) ((cirq) + (CIRQ_SPI_START)) +#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 cirq events - */ -struct cirq_events { - uint32_t spi_start; - uint32_t num_of_events; - uint32_t *wakeup_events; -}; /* * Define function prototypes. */ -void mt_cirq_enable(void); -void mt_cirq_disable(void); +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_sw_reset(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_dump_reg(void); +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 */ +#endif /* PLAT_MT_CIRQ_H */ diff --git a/plat/mediatek/mt8192/include/plat_mtk_lpm.h b/plat/mediatek/mt8192/include/plat_mtk_lpm.h new file mode 100644 index 000000000..8ba8b93a8 --- /dev/null +++ b/plat/mediatek/mt8192/include/plat_mtk_lpm.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MTK_LPM_H +#define PLAT_MTK_LPM_H + +#include <lib/psci/psci.h> +#include <lib/utils_def.h> + +#define MT_IRQ_REMAIN_MAX U(8) +#define MT_IRQ_REMAIN_CAT_LOG BIT(31) + +struct mt_irqremain { + unsigned int count; + unsigned int irqs[MT_IRQ_REMAIN_MAX]; + unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX]; + unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX]; +}; + +#define PLAT_RC_STATUS_READY BIT(0) +#define PLAT_RC_STATUS_FEATURE_EN BIT(1) +#define PLAT_RC_STATUS_UART_NONSLEEP BIT(31) + +struct mt_lpm_tz { + int (*pwr_prompt)(unsigned int cpu, const psci_power_state_t *state); + int (*pwr_reflect)(unsigned int cpu, const psci_power_state_t *state); + + int (*pwr_cpu_on)(unsigned int cpu, const psci_power_state_t *state); + int (*pwr_cpu_dwn)(unsigned int cpu, const psci_power_state_t *state); + + int (*pwr_cluster_on)(unsigned int cpu, + const psci_power_state_t *state); + int (*pwr_cluster_dwn)(unsigned int cpu, + const psci_power_state_t *state); + + int (*pwr_mcusys_on)(unsigned int cpu, const psci_power_state_t *state); + int (*pwr_mcusys_on_finished)(unsigned int cpu, + const psci_power_state_t *state); + int (*pwr_mcusys_dwn)(unsigned int cpu, + const psci_power_state_t *state); +}; + +const struct mt_lpm_tz *mt_plat_cpu_pm_init(void); + +#endif /* PLAT_MTK_LPM_H */ diff --git a/plat/mediatek/mt8192/include/plat_pm.h b/plat/mediatek/mt8192/include/plat_pm.h new file mode 100644 index 000000000..a2881cef6 --- /dev/null +++ b/plat/mediatek/mt8192/include/plat_pm.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_PM_H +#define PLAT_PM_H + +#include <lib/utils_def.h> + +#define MT_PLAT_PWR_STATE_CPU U(1) +#define MT_PLAT_PWR_STATE_CLUSTER U(2) +#define MT_PLAT_PWR_STATE_MCUSYS U(3) +#define MT_PLAT_PWR_STATE_SUSPEND2IDLE U(8) +#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND U(9) + +#define MTK_LOCAL_STATE_RUN U(0) +#define MTK_LOCAL_STATE_RET U(1) +#define MTK_LOCAL_STATE_OFF U(2) + +#define MTK_AFFLVL_CPU U(0) +#define MTK_AFFLVL_CLUSTER U(1) +#define MTK_AFFLVL_MCUSYS U(2) +#define MTK_AFFLVL_SYSTEM U(3) + +#define IS_CLUSTER_OFF_STATE(s) \ + is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_CLUSTER]) +#define IS_MCUSYS_OFF_STATE(s) \ + is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_MCUSYS]) +#define IS_SYSTEM_SUSPEND_STATE(s) \ + is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_SYSTEM]) + +#define IS_PLAT_SUSPEND_ID(stateid)\ + ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE) \ + || (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND)) + +#endif /* PLAT_PM_H */ diff --git a/plat/mediatek/mt8192/include/plat_sip_calls.h b/plat/mediatek/mt8192/include/plat_sip_calls.h new file mode 100644 index 000000000..0e423225c --- /dev/null +++ b/plat/mediatek/mt8192/include/plat_sip_calls.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_SIP_CALLS_H +#define PLAT_SIP_CALLS_H + +/******************************************************************************* + * Plat SiP function constants + ******************************************************************************/ +#define MTK_PLAT_SIP_NUM_CALLS 0 + +#endif /* PLAT_SIP_CALLS_H */ diff --git a/plat/mediatek/mt8192/include/platform_def.h b/plat/mediatek/mt8192/include/platform_def.h index 768e7cf82..51cf36136 100644 --- a/plat/mediatek/mt8192/include/platform_def.h +++ b/plat/mediatek/mt8192/include/platform_def.h @@ -23,8 +23,13 @@ #define MTK_DEV_RNG1_SIZE 0x10000000 #define MTK_DEV_RNG2_BASE 0x0c000000 #define MTK_DEV_RNG2_SIZE 0x600000 +#define MTK_MCDI_SRAM_BASE 0x11B000 +#define MTK_MCDI_SRAM_MAP_SIZE 0x1000 +#define INFRACFG_AO_BASE (IO_PHYS + 0x00001000) #define GPIO_BASE (IO_PHYS + 0x00005000) +#define SPM_BASE (IO_PHYS + 0x00006000) +#define PMIC_WRAP_BASE (IO_PHYS + 0x00026000) #define IOCFG_RM_BASE (IO_PHYS + 0x01C20000) #define IOCFG_BM_BASE (IO_PHYS + 0x01D10000) #define IOCFG_BL_BASE (IO_PHYS + 0x01D30000) @@ -67,11 +72,12 @@ ******************************************************************************/ #define PLATFORM_STACK_SIZE 0x800 -#define PLAT_MAX_PWR_LVL U(2) +#define PLAT_MAX_PWR_LVL U(3) #define PLAT_MAX_RET_STATE U(1) -#define PLAT_MAX_OFF_STATE U(2) +#define PLAT_MAX_OFF_STATE U(9) #define PLATFORM_SYSTEM_COUNT U(1) +#define PLATFORM_MCUSYS_COUNT U(1) #define PLATFORM_CLUSTER_COUNT U(1) #define PLATFORM_CLUSTER0_CORE_COUNT U(8) #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT) diff --git a/plat/mediatek/mt8192/plat_mt_cirq.c b/plat/mediatek/mt8192/plat_mt_cirq.c index 7fc060799..9002b7ee1 100644 --- a/plat/mediatek/mt8192/plat_mt_cirq.c +++ b/plat/mediatek/mt8192/plat_mt_cirq.c @@ -7,137 +7,255 @@ #include <arch_helpers.h> #include <common/debug.h> #include <drivers/arm/gic_common.h> -#include <drivers/console.h> #include <lib/mmio.h> #include <mt_gic_v3.h> -#include <mtk_plat_common.h> #include <plat_mt_cirq.h> #include <platform_def.h> static struct cirq_events cirq_all_events = { - .spi_start = CIRQ_SPI_START + .spi_start = CIRQ_SPI_START, }; - -static inline void mt_cirq_write32(uint32_t val, uint32_t addr) -{ - mmio_write_32(addr + SYS_CIRQ_BASE, val); -} - -static inline uint32_t mt_cirq_read32(uint32_t addr) -{ - return mmio_read_32(addr + SYS_CIRQ_BASE); -} - +static uint32_t already_cloned; /* - * cirq_clone_flush_check_store: - * set 1 if we need to enable clone/flush value's check + * 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.) */ -static int32_t cirq_clone_flush_check_val; +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; + } -/* - * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test. - */ -static int32_t cirq_pattern_clone_flush_check_val; + 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(); -/* - * cirq_pattern_clone_flush_check_show: set 1 if we need to do pattern test. - */ -static int32_t cirq_pattern_list; + return 0; +} /* - * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ + * 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.) */ -void mt_cirq_ack_all(void) +int mt_irq_mask_all(struct mtk_irq_mask *mask) { - unsigned int i; - - for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { - mt_cirq_write32(0xFFFFFFFF, CIRQ_ACK_BASE + (i * 4U)); + 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; } - /* make sure all cirq setting take effect before doing other things */ - dmbsy(); } -/* - * mt_cirq_enable: Enable SYS_CIRQ - */ -void mt_cirq_enable(void) +static uint32_t mt_irq_get_pol(uint32_t irq) { - uint32_t st; +#ifdef CIRQ_WITH_POLARITY + uint32_t reg; + uint32_t base = INT_POL_CTL0; - mt_cirq_ack_all(); + if (irq < 32U) { + return 0; + } - st = mt_cirq_read32(CIRQ_CON); - st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS) | - (CIRQ_CON_EDGE_ONLY << CIRQ_CON_EDGE_ONLY_BITS); + reg = ((irq - 32U) / 32U); - mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON); + return mmio_read_32(base + reg * 4U); +#else + return 0; +#endif } -/* - * mt_cirq_disable: Disable SYS_CIRQ - */ -void mt_cirq_disable(void) +unsigned int mt_irq_get_sens(unsigned int irq) { - uint32_t st; + unsigned int config; - st = mt_cirq_read32(CIRQ_CON); - st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS); + /* + * 2'b10 edge + * 2'b01 level + */ + config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U); + config = (config >> (irq % 16U) * 2U) & 0x3; - mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON); + return config; } -/* - * mt_cirq_get_mask: Get the specified SYS_CIRQ mask - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is masked - * 0: this cirq is umasked - * 2: cirq num is out of range - */ -__attribute__((weak)) unsigned int mt_cirq_get_mask(uint32_t cirq_num) +static void collect_all_wakeup_events(void) { - uint32_t st; - unsigned int val; - - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; + 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; } - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_MASK_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; -} - -/* - * mt_cirq_mask_all: Mask all interrupts on SYS_CIRQ. - */ -void mt_cirq_mask_all(void) -{ - unsigned int i; + 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; + } - for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { - mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_SET_BASE + (i * 4U)); + cirq_all_events.table[cirq_reg].used = 1U; + cirq_all_events.table[cirq_reg].reg_num = cirq_reg; + } } - /* make sure all cirq setting take effect before doing other things */ - dmbsy(); } /* - * mt_cirq_unmask_all: Unmask all interrupts on SYS_CIRQ. + * 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 */ -void mt_cirq_unmask_all(void) +#ifdef CIRQ_WITH_POLARITY +static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol) { - unsigned int i; + uint32_t base; + uint32_t bit = 1U << (cirq_num % 32U); - for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { - mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_CLR_BASE + (i * 4U)); + 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; } - /* make sure all cirq setting take effect before doing other things */ - dmbsy(); + + mmio_write_32(base, bit); + return 0; } +#endif /* * mt_cirq_mask: Mask the specified SYS_CIRQ. @@ -151,11 +269,11 @@ static int mt_cirq_mask(uint32_t cirq_num) uint32_t bit = 1U << (cirq_num % 32U); if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); return -1; } - mt_cirq_write32(bit, (cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE); + mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit); + return 0; } @@ -171,324 +289,264 @@ static int mt_cirq_unmask(uint32_t cirq_num) uint32_t bit = 1U << (cirq_num % 32U); if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); return -1; } - mt_cirq_write32(bit, (cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE); + mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit); + return 0; } -/* - * mt_cirq_set_sens: Set the sensitivity for the specified SYS_CIRQ number. - * @cirq_num: the SYS_CIRQ number to set - * @sens: sensitivity to set - * @return: - * 0: set sens success - * -1: cirq num is out of range - */ -static int mt_cirq_set_sens(uint32_t cirq_num, uint32_t sens) +uint32_t mt_irq_get_en(uint32_t irq) { - uint32_t base; - uint32_t bit = 1U << (cirq_num % 32U); + uint32_t addr, st, val; - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return -1; - } + addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U; + st = mmio_read_32(addr); - if (sens == MT_CIRQ_EDGE_SENSITIVE) { - base = (cirq_num / 32U) * 4U + CIRQ_SENS_CLR_BASE; - } else if (sens == MT_CIRQ_LEVEL_SENSITIVE) { - base = (cirq_num / 32U) * 4U + CIRQ_SENS_SET_BASE; - } else { - ERROR("[CIRQ] set_sens invalid sen value %u\n", sens); - return -1; - } + val = (st >> (irq % 32U)) & 1U; - mt_cirq_write32(bit, base); - return 0; + return val; } -/* - * mt_cirq_get_sens: Get the specified SYS_CIRQ sensitivity - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is MT_LEVEL_SENSITIVE - * 0: this cirq is MT_EDGE_SENSITIVE - * 2: cirq num is out of range - */ -__attribute__((weak)) unsigned int mt_cirq_get_sens(uint32_t cirq_num) +static void __cirq_fast_clone(void) { - uint32_t st; - unsigned int val; + struct cirq_reg *reg; + unsigned int i; - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; - } + for (i = 0U; i < CIRQ_REG_NUM ; ++i) { + uint32_t cirq_bit; - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_SENS_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; -} + reg = &cirq_all_events.table[i]; -/* - * 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 - */ -static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol) -{ - uint32_t base; - uint32_t bit = 1U << (cirq_num % 32U); + if (reg->used == 0U) { + continue; + } - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return -1; - } + mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U), + reg->sen); - 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 { - ERROR("[CIRQ] set_pol invalid polarity value %u\n", pol); - return -1; - } + 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; - mt_cirq_write32(bit, base); - return 0; -} + val = ((1U << cirq_bit) & reg->mask); -/* - * mt_cirq_get_pol: Get the specified SYS_CIRQ polarity - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is MT_CIRQ_POL_POS - * 0: this cirq is MT_CIRQ_POL_NEG - * 2: cirq num is out of range - */ -__attribute__((weak)) unsigned int mt_cirq_get_pol(uint32_t cirq_num) -{ - uint32_t st; - unsigned int val; + if (val == 0U) { + continue; + } - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; + 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); + } + } } +} - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_POL_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; +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_get_pending: Get the specified SYS_CIRQ pending - * @cirq_num: the SYS_CIRQ number to get - * @return: - * 1: this cirq is pending - * 0: this cirq is not pending - * 2: cirq num is out of range + * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ */ -static unsigned int mt_cirq_get_pending(uint32_t cirq_num) +void mt_cirq_clone_gic(void) { - uint32_t st; - unsigned int val; + cirq_fast_clone(); +} - if (cirq_num >= CIRQ_IRQ_NUM) { - ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num); - return 2; +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); } - st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_STA_BASE); - val = (st >> (cirq_num % 32U)) & 1U; - return val; + return pending_vec; +} + +static int mt_cirq_get_mask_vec(unsigned int i) +{ + return mmio_read_32((i * 4U) + CIRQ_MASK_BASE); } /* - * mt_cirq_clone_pol: Copy the polarity setting from GIC to SYS_CIRQ + * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ */ -void mt_cirq_clone_pol(void) +void mt_cirq_ack_all(void) { - uint32_t cirq_num; + uint32_t ack_vec, pend_vec, mask_vec; + unsigned int i; - for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { - mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_POS); + 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_clone_sens: Copy the sensitivity setting from GIC to SYS_CIRQ + * mt_cirq_enable: Enable SYS_CIRQ */ -void mt_cirq_clone_sens(void) +void mt_cirq_enable(void) { - uint32_t cirq_num, irq_num; - uint32_t st, val; - - for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { - irq_num = CIRQ_TO_IRQ_NUM(cirq_num); + uint32_t st; - if ((cirq_num == 0U) || (irq_num % 16U == 0U)) { - st = mmio_read_32(BASE_GICD_BASE + GICD_ICFGR + - (irq_num / 16U * 4U)); - } + /* level only */ + mt_cirq_ack_all(); - val = (st >> ((irq_num % 16U) * 2U)) & 0x2U; + st = mmio_read_32(CIRQ_CON); + /* + * CIRQ could monitor edge/level trigger + */ + st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS); - if (val) { - mt_cirq_set_sens(cirq_num, MT_CIRQ_EDGE_SENSITIVE); - } else { - mt_cirq_set_sens(cirq_num, MT_CIRQ_LEVEL_SENSITIVE); - } - } + mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK)); } /* - * mt_cirq_clone_mask: Copy the mask setting from GIC to SYS_CIRQ + * mt_cirq_disable: Disable SYS_CIRQ */ -void mt_cirq_clone_mask(void) +void mt_cirq_disable(void) { - uint32_t cirq_num, irq_num; - uint32_t st, val; + uint32_t st; - for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) { - irq_num = CIRQ_TO_IRQ_NUM(cirq_num); + st = mmio_read_32(CIRQ_CON); + st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS); + mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK)); +} - if ((cirq_num == 0U) || (irq_num % 32U == 0U)) { - st = mmio_read_32(BASE_GICD_BASE + - GICD_ISENABLER + (irq_num / 32U * 4U)); - } +void mt_irq_unmask_for_sleep_ex(uint32_t irq) +{ + uint32_t mask; - val = (st >> (irq_num % 32)) & 1U; + mask = 1U << (irq % 32U); - if (val) { - mt_cirq_unmask(cirq_num); - } else { - mt_cirq_mask(cirq_num); - } - } + mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER + + ((irq / 32U) * 4U), mask); } -/* - * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ - */ -void mt_cirq_clone_gic(void) +void mt_cirq_mask_all(void) { - mt_cirq_clone_sens(); - mt_cirq_clone_mask(); + unsigned int i; + + for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) { + mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF); + } + dsb(); } -/* - * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC - */ -void mt_cirq_flush(void) +static void cirq_fast_sw_flush(void) { + struct cirq_reg *reg; unsigned int i; - unsigned char cirq_p_val = 0U; - unsigned char irq_p_val = 0U; - uint32_t irq_p = 0U; - unsigned char pass = 1U; - uint32_t first_cirq_found = 0U; - uint32_t first_flushed_cirq; - uint32_t first_irq_flushedto; - uint32_t last_fluashed_cirq; - uint32_t last_irq_flushedto; - - if (cirq_pattern_clone_flush_check_val == 1U) { - if (cirq_pattern_list < CIRQ_IRQ_NUM) { - mt_cirq_unmask(cirq_pattern_list); - mt_cirq_set_sens(cirq_pattern_list, - MT_CIRQ_EDGE_SENSITIVE); - mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG); - mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_POS); - mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG); - } else { - ERROR("[CIRQ] no pattern to test,"); - ERROR("input pattern first\n"); - } - ERROR("[CIRQ] cirq_pattern %u, cirq_p %u,", - cirq_pattern_list, - mt_cirq_get_pending(cirq_pattern_list)); - ERROR("cirq_s %u, cirq_con 0x%x\n", - mt_cirq_get_sens(cirq_pattern_list), - mt_cirq_read32(CIRQ_CON)); - } - mt_cirq_unmask_all(); + for (i = 0U; i < CIRQ_REG_NUM ; ++i) { + uint32_t cirq_bit; - for (i = 0U; i < CIRQ_IRQ_NUM; i++) { - cirq_p_val = mt_cirq_get_pending(i); - if (cirq_p_val) { - mt_irq_set_pending(CIRQ_TO_IRQ_NUM(i)); + reg = &cirq_all_events.table[i]; + + if (reg->used == 0U) { + continue; } - if (cirq_clone_flush_check_val == 1U) { - if (cirq_p_val == 0U) { + 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; - } - irq_p = CIRQ_TO_IRQ_NUM(i); - irq_p_val = mt_irq_get_pending(irq_p); - if (cirq_p_val != irq_p_val) { - ERROR("[CIRQ] CIRQ Flush Failed "); - ERROR("%u(cirq %d)!= %u(gic %d)\n", - cirq_p_val, i, irq_p_val, - CIRQ_TO_IRQ_NUM(i)); - pass = 0; - } else { - ERROR("[CIRQ] CIRQ Flush Pass "); - ERROR("%u(cirq %d) = %u(gic %d)\n", - cirq_p_val, i, irq_p_val, - CIRQ_TO_IRQ_NUM(i)); } - if (!first_cirq_found) { - first_flushed_cirq = i; - first_irq_flushedto = irq_p; - first_cirq_found = 1U; + + 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__); } - last_fluashed_cirq = i; - last_irq_flushedto = irq_p; } } +} - if (cirq_clone_flush_check_val == 1U) { - if (first_cirq_found) { - ERROR("[CIRQ] The first flush : CIRQ%u to IRQ%u\n", - first_flushed_cirq, first_irq_flushedto); - ERROR("[CIRQ] The last flush : CIRQ%u to IRQ%u\n", - last_fluashed_cirq, last_irq_flushedto); - } else { - ERROR("[CIRQ] There are no pending "); - ERROR("interrupt in CIRQ\n"); - ERROR("[CIRQ] so no flush operation happened\n"); - } - ERROR("[CIRQ] The Flush Max Range : CIRQ"); - ERROR("%d to IRQ%d ~ CIRQ%d to IRQ%d\n", 0U, - CIRQ_TO_IRQ_NUM(0U), CIRQ_IRQ_NUM - 1U, - CIRQ_TO_IRQ_NUM(CIRQ_IRQ_NUM - 1U)); - ERROR("[CIRQ] Flush Check %s, Confirm:SPI_START_OFFSET:%d\n", - pass == 1 ? "Pass" : "Failed", CIRQ_SPI_START); - } +/* + * 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) { +#ifdef CIRQ_NEED_SW_RESET uint32_t st; - st = mt_cirq_read32(CIRQ_CON); + st = mmio_read_32(CIRQ_CON); st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS); - - mt_cirq_write32(st, CIRQ_CON); -} - -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; + mmio_write_32(CIRQ_CON, st); +#endif } diff --git a/plat/mediatek/mt8192/plat_pm.c b/plat/mediatek/mt8192/plat_pm.c index becf5d311..3ea27b6c1 100644 --- a/plat/mediatek/mt8192/plat_pm.c +++ b/plat/mediatek/mt8192/plat_pm.c @@ -5,17 +5,353 @@ */ /* common headers */ +#include <assert.h> + #include <arch_helpers.h> #include <common/debug.h> #include <drivers/gpio.h> #include <lib/psci/psci.h> -/* mediatek platform specific headers */ +/* platform specific headers */ +#include <mt_gic_v3.h> +#include <mtk_ptp3_common.h> +#include <mtspmc.h> +#include <plat/common/platform.h> +#include <plat_mtk_lpm.h> #include <plat_params.h> +#include <plat_pm.h> +#include <pmic.h> + +/* + * Cluster state request: + * [0] : The CPU requires cluster power down + * [1] : The CPU requires cluster power on + */ +#define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff) +#define coordinate_cluster_pwron() coordinate_cluster(1) +#define coordinate_cluster_pwroff() coordinate_cluster(0) + +/* platform secure entry point */ +static uintptr_t secure_entrypoint; +/* per-CPU power state */ +static unsigned int plat_power_state[PLATFORM_CORE_COUNT]; + +/* platform CPU power domain - ops */ +static const struct mt_lpm_tz *plat_mt_pm; + +#define plat_mt_pm_invoke(_name, _cpu, _state) ({ \ + int ret = -1; \ + if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \ + ret = plat_mt_pm->_name(_cpu, _state); \ + } \ + ret; }) + +#define plat_mt_pm_invoke_no_check(_name, _cpu, _state) ({ \ + if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \ + (void) plat_mt_pm->_name(_cpu, _state); \ + } \ + }) + +/* + * Common MTK_platform operations to power on/off a + * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request. + */ + +static void plat_cpu_pwrdwn_common(unsigned int cpu, + const psci_power_state_t *state, unsigned int req_pstate) +{ + assert(cpu == plat_my_core_pos()); + + plat_mt_pm_invoke_no_check(pwr_cpu_dwn, cpu, state); + + if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) || + (req_pstate == 0U)) { /* hotplug off */ + coordinate_cluster_pwroff(); + } + + /* Prevent interrupts from spuriously waking up this CPU */ + mt_gic_rdistif_save(); + gicv3_cpuif_disable(cpu); + gicv3_rdistif_off(cpu); + /* PTP3 config */ + ptp3_deinit(cpu); +} + +static void plat_cpu_pwron_common(unsigned int cpu, + const psci_power_state_t *state, unsigned int req_pstate) +{ + assert(cpu == plat_my_core_pos()); + + plat_mt_pm_invoke_no_check(pwr_cpu_on, cpu, state); + + coordinate_cluster_pwron(); + + /* Enable the GIC CPU interface */ + gicv3_rdistif_on(cpu); + gicv3_cpuif_enable(cpu); + mt_gic_rdistif_init(); + + /* + * If mcusys does power down before then restore + * all CPUs' GIC Redistributors + */ + if (IS_MCUSYS_OFF_STATE(state)) { + mt_gic_rdistif_restore_all(); + } else { + mt_gic_rdistif_restore(); + } + + /* PTP3 config */ + ptp3_init(cpu); +} + +/* + * Common MTK_platform operations to power on/off a + * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request. + */ + +static void plat_cluster_pwrdwn_common(unsigned int cpu, + const psci_power_state_t *state, unsigned int req_pstate) +{ + assert(cpu == plat_my_core_pos()); + + if (plat_mt_pm_invoke(pwr_cluster_dwn, cpu, state) != 0) { + coordinate_cluster_pwron(); + + /* TODO: return on fail. + * Add a 'return' here before adding any code following + * the if-block. + */ + } +} + +static void plat_cluster_pwron_common(unsigned int cpu, + const psci_power_state_t *state, unsigned int req_pstate) +{ + assert(cpu == plat_my_core_pos()); + + if (plat_mt_pm_invoke(pwr_cluster_on, cpu, state) != 0) { + /* TODO: return on fail. + * Add a 'return' here before adding any code following + * the if-block. + */ + } +} + +/* + * Common MTK_platform operations to power on/off a + * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request. + */ + +static void plat_mcusys_pwrdwn_common(unsigned int cpu, + const psci_power_state_t *state, unsigned int req_pstate) +{ + assert(cpu == plat_my_core_pos()); + + if (plat_mt_pm_invoke(pwr_mcusys_dwn, cpu, state) != 0) { + return; /* return on fail */ + } + + mt_gic_distif_save(); + gic_sgi_save_all(); +} + +static void plat_mcusys_pwron_common(unsigned int cpu, + const psci_power_state_t *state, unsigned int req_pstate) +{ + assert(cpu == plat_my_core_pos()); + + if (plat_mt_pm_invoke(pwr_mcusys_on, cpu, state) != 0) { + return; /* return on fail */ + } + + mt_gic_init(); + mt_gic_distif_restore(); + gic_sgi_restore_all(); + + plat_mt_pm_invoke_no_check(pwr_mcusys_on_finished, cpu, state); +} + +/* + * plat_psci_ops implementation + */ + +static void plat_cpu_standby(plat_local_state_t cpu_state) +{ + uint64_t scr; + + scr = read_scr_el3(); + write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); + + isb(); + dsb(); + wfi(); + + write_scr_el3(scr); +} + +static int plat_power_domain_on(u_register_t mpidr) +{ + unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr); + unsigned int cluster = 0U; + + if (cpu >= PLATFORM_CORE_COUNT) { + return PSCI_E_INVALID_PARAMS; + } + + if (!spm_get_cluster_powerstate(cluster)) { + spm_poweron_cluster(cluster); + } + + /* init CPU reset arch as AARCH64 */ + mcucfg_init_archstate(cluster, cpu, true); + mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); + spm_poweron_cpu(cluster, cpu); + + return PSCI_E_SUCCESS; +} + +static void plat_power_domain_on_finish(const psci_power_state_t *state) +{ + unsigned long mpidr = read_mpidr_el1(); + unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr); + + assert(cpu < PLATFORM_CORE_COUNT); + + /* Allow IRQs to wakeup this core in IDLE flow */ + mcucfg_enable_gic_wakeup(0U, cpu); + + if (IS_CLUSTER_OFF_STATE(state)) { + plat_cluster_pwron_common(cpu, state, 0U); + } + + plat_cpu_pwron_common(cpu, state, 0U); +} + +static void plat_power_domain_off(const psci_power_state_t *state) +{ + unsigned long mpidr = read_mpidr_el1(); + unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr); + + assert(cpu < PLATFORM_CORE_COUNT); + + plat_cpu_pwrdwn_common(cpu, state, 0U); + spm_poweroff_cpu(0U, cpu); + + /* prevent unintended IRQs from waking up the hot-unplugged core */ + mcucfg_disable_gic_wakeup(0U, cpu); + + if (IS_CLUSTER_OFF_STATE(state)) { + plat_cluster_pwrdwn_common(cpu, state, 0U); + } +} + +static void plat_power_domain_suspend(const psci_power_state_t *state) +{ + unsigned int cpu = plat_my_core_pos(); + + assert(cpu < PLATFORM_CORE_COUNT); + + plat_mt_pm_invoke_no_check(pwr_prompt, cpu, state); + + /* Perform the common CPU specific operations */ + plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]); + + if (IS_CLUSTER_OFF_STATE(state)) { + /* Perform the common cluster specific operations */ + plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]); + } + + if (IS_MCUSYS_OFF_STATE(state)) { + /* Perform the common mcusys specific operations */ + plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]); + } +} + +static void plat_power_domain_suspend_finish(const psci_power_state_t *state) +{ + unsigned int cpu = plat_my_core_pos(); + + assert(cpu < PLATFORM_CORE_COUNT); + + if (IS_MCUSYS_OFF_STATE(state)) { + /* Perform the common mcusys specific operations */ + plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]); + } + + if (IS_CLUSTER_OFF_STATE(state)) { + /* Perform the common cluster specific operations */ + plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]); + } + + /* Perform the common CPU specific operations */ + plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]); + + plat_mt_pm_invoke_no_check(pwr_reflect, cpu, state); +} + +static int plat_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + unsigned int pstate = psci_get_pstate_type(power_state); + unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state); + unsigned int cpu = plat_my_core_pos(); + + if (aff_lvl > PLAT_MAX_PWR_LVL) { + return PSCI_E_INVALID_PARAMS; + } + + if (pstate == PSTATE_TYPE_STANDBY) { + req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE; + } else { + unsigned int i; + unsigned int pstate_id = psci_get_pstate_id(power_state); + plat_local_state_t s = MTK_LOCAL_STATE_OFF; + + /* Use pstate_id to be power domain state */ + if (pstate_id > s) { + s = (plat_local_state_t)pstate_id; + } + + for (i = 0U; i <= aff_lvl; i++) { + req_state->pwr_domain_state[i] = s; + } + } + + plat_power_state[cpu] = power_state; + return PSCI_E_SUCCESS; +} + +static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + unsigned int lv; + unsigned int cpu = plat_my_core_pos(); + + for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) { + req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE; + } + + plat_power_state[cpu] = + psci_make_powerstate( + MT_PLAT_PWR_STATE_SYSTEM_SUSPEND, + PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL); + + flush_dcache_range((uintptr_t) + &plat_power_state[cpu], + sizeof(plat_power_state[cpu])); +} + +static void __dead2 plat_mtk_system_off(void) +{ + INFO("MTK System Off\n"); + + pmic_power_off(); + + wfi(); + ERROR("MTK System Off: operation not handled.\n"); + panic(); +} -/******************************************************************************* - * MTK handlers to shutdown/reboot the system - ******************************************************************************/ static void __dead2 plat_mtk_system_reset(void) { struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset(); @@ -29,18 +365,35 @@ static void __dead2 plat_mtk_system_reset(void) panic(); } -/******************************************************************************* - * MTK_platform handler called when an affinity instance is about to be turned - * on. The level and mpidr determine the affinity instance. - ******************************************************************************/ -static const plat_psci_ops_t plat_plat_pm_ops = { - .system_reset = plat_mtk_system_reset, +static const plat_psci_ops_t plat_psci_ops = { + .system_reset = plat_mtk_system_reset, + .cpu_standby = plat_cpu_standby, + .pwr_domain_on = plat_power_domain_on, + .pwr_domain_on_finish = plat_power_domain_on_finish, + .pwr_domain_off = plat_power_domain_off, + .pwr_domain_suspend = plat_power_domain_suspend, + .pwr_domain_suspend_finish = plat_power_domain_suspend_finish, + .system_off = plat_mtk_system_off, + .validate_power_state = plat_validate_power_state, + .get_sys_suspend_power_state = plat_get_sys_suspend_power_state }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { - *psci_ops = &plat_plat_pm_ops; + *psci_ops = &plat_psci_ops; + secure_entrypoint = sec_entrypoint; + + /* + * init the warm reset config for boot CPU + * reset arch as AARCH64 + * reset addr as function bl31_warm_entrypoint() + */ + mcucfg_init_archstate(0U, 0U, true); + mcucfg_set_bootaddr(0U, 0U, secure_entrypoint); + + spmc_init(); + plat_mt_pm = mt_plat_cpu_pm_init(); return 0; } diff --git a/plat/mediatek/mt8192/plat_sip_calls.c b/plat/mediatek/mt8192/plat_sip_calls.c new file mode 100644 index 000000000..f97684f77 --- /dev/null +++ b/plat/mediatek/mt8192/plat_sip_calls.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <common/runtime_svc.h> + +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) +{ + + switch (smc_fid) { + default: + ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); + break; + } + + SMC_RET1(handle, SMC_UNK); +} diff --git a/plat/mediatek/mt8192/plat_topology.c b/plat/mediatek/mt8192/plat_topology.c index aa4975e80..8c1231a6e 100644 --- a/plat/mediatek/mt8192/plat_topology.c +++ b/plat/mediatek/mt8192/plat_topology.c @@ -17,6 +17,8 @@ const unsigned char mtk_power_domain_tree_desc[] = { /* Number of root nodes */ PLATFORM_SYSTEM_COUNT, /* Number of children for the root node */ + PLATFORM_MCUSYS_COUNT, + /* Number of children for the mcusys node */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, diff --git a/plat/mediatek/mt8192/platform.mk b/plat/mediatek/mt8192/platform.mk index 7544b2658..191895a21 100644 --- a/plat/mediatek/mt8192/platform.mk +++ b/plat/mediatek/mt8192/platform.mk @@ -10,8 +10,14 @@ MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT} PLAT_INCLUDES := -I${MTK_PLAT}/common/ \ -I${MTK_PLAT_SOC}/include/ \ -I${MTK_PLAT_SOC}/drivers/ \ + -I${MTK_PLAT_SOC}/drivers/dcm \ -I${MTK_PLAT_SOC}/drivers/gpio/ \ - -I${MTK_PLAT_SOC}/drivers/timer/ + -I${MTK_PLAT_SOC}/drivers/mcdi/ \ + -I${MTK_PLAT_SOC}/drivers/pmic/ \ + -I${MTK_PLAT_SOC}/drivers/ptp3/ \ + -I${MTK_PLAT_SOC}/drivers/spmc/ \ + -I${MTK_PLAT_SOC}/drivers/timer/ \ + -I${MTK_PLAT_SOC}/drivers/uart/ GICV3_SUPPORT_GIC600 := 1 include drivers/arm/gic/v3/gicv3.mk @@ -23,25 +29,38 @@ PLAT_BL_COMMON_SOURCES := ${GICV3_SOURCES} \ plat/common/plat_psci_common.c BL31_SOURCES += common/desc_image_load.c \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ drivers/gpio/gpio.c \ lib/bl_aux_params/bl_aux_params.c \ lib/cpus/aarch64/cortex_a55.S \ lib/cpus/aarch64/cortex_a76.S \ plat/common/plat_gicv3.c \ + ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init_v2.c \ + ${MTK_PLAT}/common/drivers/uart/uart.c \ ${MTK_PLAT}/common/mtk_plat_common.c \ + ${MTK_PLAT}/common/mtk_sip_svc.c \ ${MTK_PLAT}/common/params_setup.c \ ${MTK_PLAT_SOC}/aarch64/platform_common.c \ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \ ${MTK_PLAT_SOC}/bl31_plat_setup.c \ + ${MTK_PLAT_SOC}/drivers/pmic/pmic.c \ ${MTK_PLAT_SOC}/plat_pm.c \ ${MTK_PLAT_SOC}/plat_topology.c \ ${MTK_PLAT_SOC}/plat_mt_gic.c \ ${MTK_PLAT_SOC}/plat_mt_cirq.c \ + ${MTK_PLAT_SOC}/plat_sip_calls.c \ + ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c \ + ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c \ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \ + ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c \ + ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c \ + ${MTK_PLAT_SOC}/drivers/mcdi/mt_mcdi.c \ + ${MTK_PLAT_SOC}/drivers/ptp3/mtk_ptp3_main.c \ + ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c \ ${MTK_PLAT_SOC}/drivers/timer/mt_timer.c - # Configs for A76 and A55 HW_ASSISTED_COHERENCY := 1 USE_COHERENT_MEM := 0 diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c index b6d8770cc..8272d6221 100644 --- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c +++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c @@ -104,9 +104,12 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, else if (ret != FSBL_HANDOFF_SUCCESS) panic(); } - - NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); - NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); + if (bl32_image_ep_info.pc) { + VERBOSE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); + } + if (bl33_image_ep_info.pc) { + VERBOSE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); + } } /* Enable the test setup */ diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h index 5e7254e5c..461439530 100644 --- a/plat/xilinx/zynqmp/include/zynqmp_def.h +++ b/plat/xilinx/zynqmp/include/zynqmp_def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -341,8 +341,9 @@ #define PGGS_BASEADDR (0xFFD80050U) #define PGGS_NUM_REGS U(4) -/* Warm restart boot health status register and mask */ -#define PM_BOOT_HEALTH_STATUS_REG (GGS_BASEADDR + U(0x10)) +/* PMU GGS4 register 4 is used for warm restart boot health status */ +#define PMU_GLOBAL_GEN_STORAGE4 (GGS_BASEADDR + 0x10) +/* Warm restart boot health status mask */ #define PM_BOOT_HEALTH_STATUS_MASK U(0x01) /*AFI registers */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c index 852f92763..f2dfbb17b 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -129,12 +129,26 @@ .div = NA_DIV, \ } -#define GENERIC_DIV(id) \ +#define GENERIC_DIV1 \ { \ - .type = TYPE_DIV##id, \ - .offset = PERIPH_DIV##id##_SHIFT, \ - .width = PERIPH_DIV##id##_WIDTH, \ + .type = TYPE_DIV1, \ + .offset = PERIPH_DIV1_SHIFT, \ + .width = PERIPH_DIV1_WIDTH, \ + .clkflags = CLK_SET_RATE_NO_REPARENT | \ + CLK_IS_BASIC, \ + .typeflags = CLK_DIVIDER_ONE_BASED | \ + CLK_DIVIDER_ALLOW_ZERO, \ + .mult = NA_MULT, \ + .div = NA_DIV, \ + } + +#define GENERIC_DIV2 \ + { \ + .type = TYPE_DIV2, \ + .offset = PERIPH_DIV2_SHIFT, \ + .width = PERIPH_DIV2_WIDTH, \ .clkflags = CLK_SET_RATE_NO_REPARENT | \ + CLK_SET_RATE_PARENT | \ CLK_IS_BASIC, \ .typeflags = CLK_DIVIDER_ONE_BASED | \ CLK_DIVIDER_ALLOW_ZERO, \ @@ -340,25 +354,25 @@ static struct pm_clock_node acpu_nodes[] = { static struct pm_clock_node generic_mux_div_nodes[] = { GENERIC_MUX, - GENERIC_DIV(1), + GENERIC_DIV1, }; static struct pm_clock_node generic_mux_div_gate_nodes[] = { GENERIC_MUX, - GENERIC_DIV(1), + GENERIC_DIV1, GENERIC_GATE, }; static struct pm_clock_node generic_mux_div_unused_gate_nodes[] = { GENERIC_MUX, - GENERIC_DIV(1), + GENERIC_DIV1, IGNORE_UNUSED_GATE, }; static struct pm_clock_node generic_mux_div_div_gate_nodes[] = { GENERIC_MUX, - GENERIC_DIV(1), - GENERIC_DIV(2), + GENERIC_DIV1, + GENERIC_DIV2, GENERIC_GATE, }; @@ -410,8 +424,8 @@ static struct pm_clock_node dp_audio_video_ref_nodes[] = { static struct pm_clock_node usb_nodes[] = { GENERIC_MUX, - GENERIC_DIV(1), - GENERIC_DIV(2), + GENERIC_DIV1, + GENERIC_DIV2, { .type = TYPE_GATE, .offset = USB_GATE_SHIFT, @@ -2435,7 +2449,8 @@ enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks) enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name) { if (clock_id == CLK_MAX) - memcpy(name, END_OF_CLK, CLK_NAME_LEN); + memcpy(name, END_OF_CLK, sizeof(END_OF_CLK) > CLK_NAME_LEN ? + CLK_NAME_LEN : sizeof(END_OF_CLK)); else if (!pm_clock_valid(clock_id)) memset(name, 0, CLK_NAME_LEN); else if (clock_id < CLK_MAX_OUTPUT_CLK) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c index 60e80d907..9da904eb5 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -575,7 +575,7 @@ static enum pm_ret_status pm_ioctl_ulpi_reset(void) */ static enum pm_ret_status pm_ioctl_set_boot_health_status(unsigned int value) { - return pm_mmio_write(PM_BOOT_HEALTH_STATUS_REG, + return pm_mmio_write(PMU_GLOBAL_GEN_STORAGE4, PM_BOOT_HEALTH_STATUS_MASK, value); } |