diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 574a2bcdfb8..eee4a38cee1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -270,6 +270,7 @@ jobs: _make PLATFORM=nuvoton _make PLATFORM=d06 _make PLATFORM=d06 CFG_HISILICON_ACC_V3=y + _make PLATFORM=telechips-tcc805x export ARCH=riscv unset CROSS_COMPILE32 diff --git a/MAINTAINERS b/MAINTAINERS index 6726c8f6abd..1a71d42098e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -330,6 +330,13 @@ R: Neal Liu [@Neal-liu] S: Maintained F: core/arch/arm/plat-aspeed/ +Telechips TCC805x +R: Sungmin Han [@meeneemaru] +R: GY Hwang [@hwang-telechips] +S: Maintained +F: core/arch/arm/plat-telechips/ +F: core/drivers/openedges_omc.c + RISC-V R: Marouene Boubakri [@maroueneboubakri] S: Maintained diff --git a/core/arch/arm/plat-telechips/conf.mk b/core/arch/arm/plat-telechips/conf.mk new file mode 100644 index 00000000000..656dd9afdc4 --- /dev/null +++ b/core/arch/arm/plat-telechips/conf.mk @@ -0,0 +1,38 @@ +ifeq ($(PLATFORM_FLAVOR),tcc805x) +CFG_PL011 ?= y +CFG_OPENEDGES_OMC ?= y +CFG_ARM_SMCCC_TRNG ?= y + +$(call force,CFG_CORE_LARGE_PHYS_ADDR,y) +$(call force,CFG_CORE_ARM64_PA_BITS,35) +$(call force,CFG_TEE_CORE_NB_CORE,4) + +CFG_TZDRAM_START ?= 0x2E000000 +CFG_TZDRAM_SIZE ?= 0x02000000 + +include core/arch/arm/cpu/cortex-armv8-0.mk +$(call force,CFG_ARM64_core,y) + +TCMKTOOL_IMGNAME ?= A72-OPTEE +else +$(error Unsupported PLATFORM_FLAVOR "$(PLATFORM_FLAVOR)") +endif + +$(call force,CFG_SECURE_TIME_SOURCE_CNTPCT,y) +$(call force,CFG_GIC,y) +$(call force,CFG_CACHE_API,y) +$(call force,CFG_CORE_RESERVED_SHM,n) + +ifeq ($(platform-flavor-armv8),1) +$(call force,CFG_WITH_ARM_TRUSTED_FW,y) +$(call force,CFG_CRYPTO_WITH_CE,y) +endif + +CFG_NUM_THREADS ?= $(CFG_TEE_CORE_NB_CORE) +CFG_SECSTOR_TA ?= n +CFG_CORE_HEAP_SIZE ?= 1048576 +CFG_WITH_STATS ?= y + +ifeq ($(CFG_RPMB_FS),y) +CFG_IN_TREE_EARLY_TAS += avb/023f8f1a-292a-432b-8fc4-de8471358067 +endif diff --git a/core/arch/arm/plat-telechips/drivers/include/drivers/tcc_otp.h b/core/arch/arm/plat-telechips/drivers/include/drivers/tcc_otp.h new file mode 100644 index 00000000000..da87c09c4fa --- /dev/null +++ b/core/arch/arm/plat-telechips/drivers/include/drivers/tcc_otp.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#ifndef __DRIVERS_TCC_OTP_H +#define __DRIVERS_TCC_OTP_H + +#include + +TEE_Result tcc_otp_read_128(uint32_t offset, uint32_t *buf); +TEE_Result tcc_otp_write_128(uint32_t offset, const uint32_t *buf); + +#endif /* __DRIVERS_TCC_OTP_H */ diff --git a/core/arch/arm/plat-telechips/drivers/sub.mk b/core/arch/arm/plat-telechips/drivers/sub.mk new file mode 100644 index 00000000000..b394c7ffe96 --- /dev/null +++ b/core/arch/arm/plat-telechips/drivers/sub.mk @@ -0,0 +1 @@ +srcs-y += tcc_otp.c diff --git a/core/arch/arm/plat-telechips/drivers/tcc_otp.c b/core/arch/arm/plat-telechips/drivers/tcc_otp.c new file mode 100644 index 00000000000..91a94cd6ba4 --- /dev/null +++ b/core/arch/arm/plat-telechips/drivers/tcc_otp.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#include +#include +#include +#include +#include +#include + +#define OTP_CTRL_SIZE U(0x1000) +#define OTP_CMD_SIZE U(0x1000) + +#define GENERAL_STATUS U(0x0) +#define READ_STATUS U(0x4) +#define PROG_STATUS U(0x8) +#define OTP_ADDRESS U(0x10) +#define OTP_CONTROL U(0x14) +#define READ_DATA_PAYLOAD0 U(0x20) +#define READ_DATA_PAYLOAD1 U(0x24) +#define READ_DATA_PAYLOAD2 U(0x28) +#define READ_DATA_PAYLOAD3 U(0x2C) +#define READ_ADMIN_INFO0 U(0x30) +#define READ_ADMIN_INFO1 U(0x34) +#define READ_ADMIN_INFO2 U(0x38) +#define READ_ADMIN_INFO3 U(0x3C) +#define PROG_DATA_PAYLOAD0 U(0x40) +#define PROG_DATA_PAYLOAD1 U(0x44) +#define PROG_DATA_PAYLOAD2 U(0x48) +#define PROG_DATA_PAYLOAD3 U(0x4C) +#define PROG_ADMIN_INFO0 U(0x50) +#define PROG_ADMIN_INFO1 U(0x54) +#define PROG_ADMIN_INFO2 U(0x58) +#define PROG_ADMIN_INFO3 U(0x5C) + +/* GENERAL_STATUS */ +#define STATUS_READY BIT(0) + +/* READ_STATUS */ +#define DATA_ERR BIT(3) +#define PERMISSION_ERR BIT(0) + +/* OTP_CONTROL Register */ +#define CTRL_DONE BIT(16) +#define CTRL_START BIT(0) +#define CTRL_CMD_PROG SHIFT_U32(0xA, 4) +#define CTRL_CMD_READ SHIFT_U32(0xF, 4) + +/* Admin Info */ +#define ADMIN_VALID BIT(0) + +/* Write Protection Control */ +#define EXT_WP BIT(30) +#define SOFT_WP BIT(3) + +#define IS_16BYTE_ALIGNED(x) IS_ALIGNED(x, 16) + +register_phys_mem(MEM_AREA_IO_SEC, OTP_CMD_BASE, OTP_CMD_SIZE); + +static void wait_for_ready(vaddr_t reg) +{ + while (!(io_read32(reg + GENERAL_STATUS) & STATUS_READY)) + udelay(1); +} + +static void wait_for_done(vaddr_t reg) +{ + while (!(io_read32(reg + OTP_CONTROL) & CTRL_DONE)) + udelay(1); +} + +TEE_Result tcc_otp_read_128(uint32_t offset, uint32_t *buf) +{ + vaddr_t reg = (vaddr_t)phys_to_virt_io(OTP_CMD_BASE, OTP_CMD_SIZE); + uint32_t status = 0; + uint32_t admin_info0 = 0; + + if (!IS_16BYTE_ALIGNED(offset) || offset >= OTPROM_128_LIMIT || + offset < OTPROM_128_START || !buf || !reg) { + EMSG("Invalid parameters"); + return TEE_ERROR_BAD_PARAMETERS; + } + + wait_for_ready(reg); + io_write32(reg + OTP_ADDRESS, offset); + io_write32(reg + OTP_CONTROL, CTRL_CMD_READ | CTRL_START); + wait_for_done(reg); + + admin_info0 = io_read32(reg + READ_ADMIN_INFO0); + if (!(admin_info0 & ADMIN_VALID)) { + if (!admin_info0 && !io_read32(reg + READ_STATUS)) + return TEE_ERROR_NO_DATA; + return TEE_ERROR_BAD_STATE; + } + + status = io_read32(reg + READ_STATUS); + if (status & (DATA_ERR | PERMISSION_ERR)) { + EMSG("Failed to read OTP (%#"PRIx32")", status); + return TEE_ERROR_BAD_STATE; + } + + buf[0] = io_read32(reg + READ_DATA_PAYLOAD0); + buf[1] = io_read32(reg + READ_DATA_PAYLOAD1); + buf[2] = io_read32(reg + READ_DATA_PAYLOAD2); + buf[3] = io_read32(reg + READ_DATA_PAYLOAD3); + + return TEE_SUCCESS; +} + +TEE_Result tcc_otp_write_128(uint32_t offset, const uint32_t *buf) +{ + vaddr_t reg = (vaddr_t)phys_to_virt_io(OTP_CMD_BASE, OTP_CMD_SIZE); + vaddr_t ctrl = (vaddr_t)phys_to_virt_io(OTP_CTRL_BASE, OTP_CTRL_SIZE); + + if (!IS_16BYTE_ALIGNED(offset) || offset >= OTPROM_128_LIMIT || + offset < OTPROM_128_START || !buf || !reg) { + EMSG("Invalid parameters"); + return TEE_ERROR_BAD_PARAMETERS; + } + + if (io_read32(ctrl) & EXT_WP) { + EMSG("EXT_WP is high"); + return TEE_ERROR_BAD_STATE; + } + + wait_for_ready(reg); + io_clrbits32(ctrl, SOFT_WP); + io_write32(reg + OTP_ADDRESS, offset); + io_write32(reg + PROG_DATA_PAYLOAD0, buf[0]); + io_write32(reg + PROG_DATA_PAYLOAD1, buf[1]); + io_write32(reg + PROG_DATA_PAYLOAD2, buf[2]); + io_write32(reg + PROG_DATA_PAYLOAD3, buf[3]); + io_write32(reg + PROG_ADMIN_INFO0, 0); + io_write32(reg + PROG_ADMIN_INFO1, 0); + io_write32(reg + PROG_ADMIN_INFO2, 0); + io_write32(reg + PROG_ADMIN_INFO3, 0); + io_write32(reg + OTP_CONTROL, CTRL_CMD_PROG | CTRL_START); + wait_for_done(reg); + io_setbits32(ctrl, SOFT_WP); + + return TEE_SUCCESS; +} diff --git a/core/arch/arm/plat-telechips/link.mk b/core/arch/arm/plat-telechips/link.mk new file mode 100644 index 00000000000..60386bbc49b --- /dev/null +++ b/core/arch/arm/plat-telechips/link.mk @@ -0,0 +1,9 @@ +include core/arch/arm/kernel/link.mk + +all: $(link-out-dir)/optee.rom +cleanfiles += $(link-out-dir)/optee.rom +$(link-out-dir)/optee.rom: $(link-out-dir)/tee-pager_v2.bin + @$(cmd-echo-silent) ' GEN $@' + $(q)$(PYTHON3) core/arch/arm/plat-telechips/scripts/tcmktool.py $< $@ $(TCMKTOOL_IMGNAME) \ + $(CFG_OPTEE_REVISION_MAJOR).$(CFG_OPTEE_REVISION_MINOR)$(CFG_OPTEE_REVISION_EXTRA) \ + $(CFG_TZDRAM_START) $(PLATFORM_FLAVOR) diff --git a/core/arch/arm/plat-telechips/main.c b/core/arch/arm/plat-telechips/main.c new file mode 100644 index 00000000000..5d2e0667f47 --- /dev/null +++ b/core/arch/arm/plat-telechips/main.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +register_phys_mem(MEM_AREA_IO_SEC, TCC_IO_BASE, TCC_IO_SIZE); +#if defined(TZC_BASE) +register_phys_mem(MEM_AREA_IO_SEC, TZC_BASE, TZC_SIZE); +#endif + +register_ddr(DRAM0_BASE, DRAM0_SIZE); +#if defined(DRAM1_BASE) +register_ddr(DRAM1_BASE, DRAM1_SIZE); +#endif + +static bool huk_is_ready; +static uint32_t plat_huk[OTP_DATA_TEE_HUK_SIZE / sizeof(uint32_t)]; + +void boot_primary_init_intc(void) +{ + gic_init(GICC_BASE, GICD_BASE); +} + +void boot_secondary_init_intc(void) +{ + gic_init_per_cpu(); +} + +void plat_console_init(void) +{ +#if defined(CFG_PL011) + static struct pl011_data console_data; + + pl011_init(&console_data, CONSOLE_UART_BASE, CONSOLE_UART_CLK_IN_HZ, + CONSOLE_BAUDRATE); + register_serial_console(&console_data.chip); +#endif +} + +TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) +{ + static_assert(sizeof(plat_huk) == sizeof(hwkey->data)); + + if (!huk_is_ready) + return TEE_ERROR_GENERIC; + + memcpy(hwkey->data, plat_huk, OTP_DATA_TEE_HUK_SIZE); + return TEE_SUCCESS; +} + +static TEE_Result init_huk(void) +{ + TEE_Result res = TEE_ERROR_GENERIC; + + res = tcc_otp_read_128(OTP_DATA_TEE_HUK_OFFSET, plat_huk); + if (res == TEE_ERROR_NO_DATA) { + IMSG("There is no HUK in OTP. Starting HUK Provisioning"); + if (!crypto_rng_read(plat_huk, OTP_DATA_TEE_HUK_SIZE)) { + tcc_otp_write_128(OTP_DATA_TEE_HUK_OFFSET, plat_huk); + res = tcc_otp_read_128(OTP_DATA_TEE_HUK_OFFSET, + plat_huk); + if (res != TEE_SUCCESS) + EMSG("Failed to store HUK to OTP"); + } else { + EMSG("Failed to generate random number for HUK"); + } + } + + if (res == TEE_SUCCESS) + huk_is_ready = true; + else + EMSG("Failed to get HUK from OTP"); + + return res; +} +service_init(init_huk); diff --git a/core/arch/arm/plat-telechips/plat_tzc.c b/core/arch/arm/plat-telechips/plat_tzc.c new file mode 100644 index 00000000000..8212719b9f6 --- /dev/null +++ b/core/arch/arm/plat-telechips/plat_tzc.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#include +#include +#include +#include +#include +#include + +#define NSEC_ALL_ACCESS UINT32_MAX + +static void tzc_protect_teeos(void) +{ + struct omc_region_config cfg = { + .filters = GENMASK_32(TZC_OMC_FILTERS - 1, 0), + .base = CFG_TZDRAM_START - DRAM0_BASE, + .top = (CFG_TZDRAM_START + CFG_TZDRAM_SIZE - 1) - DRAM0_BASE, + .ns_device_access = 0, + .flags = OMC_FLAG_RELATIVE_ADDR, + }; + + omc_configure_region(TZC_TEEOS_REGION_NUM, &cfg); +} + +static enum itr_return tzc_it_handler(struct itr_handler *h) +{ + uint8_t filter = UINT8_MAX; + enum itr_return ret = ITRR_NONE; + + switch (h->it) { + case TZC_OMC_INT_0: + filter = 0; + break; +#if defined(TZC_OMC_INT_1) + case TZC_OMC_INT_1: + filter = 1; + break; +#endif +#if defined(TZC_OMC_INT_2) + case TZC_OMC_INT_2: + filter = 2; + break; +#endif +#if defined(TZC_OMC_INT_3) + case TZC_OMC_INT_3: + filter = 3; + break; +#endif + default: + break; + } + + if (filter != UINT8_MAX) { + EMSG("OMC(%"PRIu8") TZC permission failure", filter); + omc_fail_dump(filter); + omc_int_clear(filter); + + ret = ITRR_HANDLED; + } + + return ret; +} + +static struct itr_handler tzc_itr_handler[] = { + { + .it = TZC_OMC_INT_0, + .handler = tzc_it_handler, + }, +#if defined(TZC_OMC_INT_1) + { + .it = TZC_OMC_INT_1, + .handler = tzc_it_handler, + }, +#endif +#if defined(TZC_OMC_INT_2) + { + .it = TZC_OMC_INT_2, + .handler = tzc_it_handler, + }, +#endif +#if defined(TZC_OMC_INT_3) + { + .it = TZC_OMC_INT_3, + .handler = tzc_it_handler, + }, +#endif +}; + +static TEE_Result tzc_configure(void) +{ + vaddr_t va = 0; + uint8_t filter = 0; + struct omc_region_config cfg = { + .filters = GENMASK_32(TZC_OMC_FILTERS - 1, 0), + .base = 0, + .top = UINT64_MAX, + .ns_device_access = NSEC_ALL_ACCESS, + .flags = 0, + }; + + DMSG("Initializing TZC"); + + va = (vaddr_t)phys_to_virt_io(TZC_OMC_BASE, + TZC_OMC_FILTERS * TZC_OMC_FILTER_OFFS); + if (!va) + panic(); + + omc_init(va, TZC_OMC_FILTER_OFFS, TZC_OMC_FILTERS); + omc_configure_region(0, &cfg); + tzc_protect_teeos(); + + for (filter = 0; filter < ARRAY_SIZE(tzc_itr_handler); filter++) { + interrupt_add_handler_with_chip(interrupt_get_main_chip(), + &tzc_itr_handler[filter]); + interrupt_enable(interrupt_get_main_chip(), + tzc_itr_handler[filter].it); + } + omc_set_action(OMC_ACTION_INT); + + return TEE_SUCCESS; +} +service_init(tzc_configure); diff --git a/core/arch/arm/plat-telechips/scripts/tcmktool.py b/core/arch/arm/plat-telechips/scripts/tcmktool.py new file mode 100755 index 00000000000..5934cfe72ce --- /dev/null +++ b/core/arch/arm/plat-telechips/scripts/tcmktool.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2024, Telechips Inc. +# + +import sys +from hashlib import sha256 + +ALIGN_SIZE = 64 +FOOTER_SIZE = 128 + + +def calc_hash(inputfile): + sha = sha256() + inputfile.seek(0) + while True: + buf = inputfile.read(ALIGN_SIZE) + if len(buf) == 0: + break + sha.update(buf.ljust(ALIGN_SIZE, b'\0')) + return sha.digest() + + +def fill_dummy_cert(outputfile): + outputfile.write(b'CERT'.ljust(256, b'\0')) + return 0 + + +def fill_header(outputfile, inputfile, argv): + imagename = bytes(argv[3], 'utf-8') + imageversion = bytes(argv[4], 'utf-8') + targetaddress = int(argv[5], 16) + socname = bytes(argv[6], 'utf-8') + inputfile.seek(0, 2) + offset = 4096 # Min: 256 + length = (inputfile.tell() + (ALIGN_SIZE - 1)) & ~(ALIGN_SIZE - 1) + length += FOOTER_SIZE + buf = bytearray(offset - outputfile.tell()) + buf[0:4] = b'HDR\0' # Marker + buf[4:8] = length.to_bytes(4, byteorder='little') + buf[8:12] = offset.to_bytes(4, byteorder='little') + buf[16:20] = socname.ljust(4, b'\0')[-4:] + buf[20:32] = imagename.ljust(12, b'\0')[0:12] + buf[32:48] = imageversion.ljust(16, b'\0')[0:16] + buf[48:56] = targetaddress.to_bytes(8, byteorder='little') + buf[96:128] = calc_hash(inputfile) + outputfile.write(buf) + return 0 + + +def fill_image(outputfile, inputfile): + inputfile.seek(0) + while True: + buf = inputfile.read(ALIGN_SIZE) + if len(buf) == 0: + break + outputfile.write(buf.ljust(ALIGN_SIZE, b'\0')) + return 0 + + +def fill_dummy_footer(outputfile): + outputfile.write(bytearray(FOOTER_SIZE)) + return 0 + + +def make_image(inputfile, outputfile, argv): + if fill_dummy_cert(outputfile) != 0: + return -1 + if fill_header(outputfile, inputfile, argv) != 0: + return -2 + if fill_image(outputfile, inputfile) != 0: + return -3 + if fill_dummy_footer(outputfile) != 0: + return -4 + return 0 + + +def print_help(): + print("") + print("Telechips Image Maker") + print("") + print("Usage: python tcmktool.py [INPUT] [OUTPUT] [NAME] [VERSION]" + + " [TARGET_ADDRESS] [SOC_NAME]") + print("") + print(" INPUT input file name.") + print(" OUTPUT output file name.") + print(" NAME image name.") + print(" VERSION string version. (max 16 bytes)") + print(" TARGET_ADDRESS target address") + print(" SOC_NAME SoC name. (only the last 4 bytes are used") + + +def main(argc, argv): + ret = -1 + + if argc != 7: + print_help() + return -1 + + try: + with open(argv[1], "rb") as inputfile: + with open(argv[2], "wb") as outputfile: + ret = make_image(inputfile, outputfile, argv) + except Exception as e: + if 'inputfile' not in locals(): + print("ERROR: input file open error\n") + elif 'outputfile' not in locals(): + print("ERROR: output file open error\n") + else: + print(e) + + if ret == 0: + print("{} was generated successfilly\n".format(argv[2])) + else: + print("Failed to generate output file (error code: {})\n".format(ret)) + + return ret + + +if (__name__ == "__main__"): + exit(main(len(sys.argv), sys.argv)) diff --git a/core/arch/arm/plat-telechips/sub.mk b/core/arch/arm/plat-telechips/sub.mk new file mode 100644 index 00000000000..827fcd79c7f --- /dev/null +++ b/core/arch/arm/plat-telechips/sub.mk @@ -0,0 +1,7 @@ +global-incdirs-y += $(PLATFORM_FLAVOR) +global-incdirs-y += drivers/include + +srcs-y += main.c +srcs-y += plat_tzc.c + +subdirs-y += drivers diff --git a/core/arch/arm/plat-telechips/tcc805x/otprom.h b/core/arch/arm/plat-telechips/tcc805x/otprom.h new file mode 100644 index 00000000000..312f99237c5 --- /dev/null +++ b/core/arch/arm/plat-telechips/tcc805x/otprom.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#ifndef TCC805X_OTPROM_H +#define TCC805X_OTPROM_H + +#include + +#define OTPROM_MAX U(0x4000) +#define OTPROM_128_START U(0x1000) +#define OTPROM_128_LIMIT U(0x2000) + +/* HUK */ +#define OTP_DATA_TEE_HUK_OFFSET U(0x1ED0) +#define OTP_DATA_TEE_HUK_SIZE U(0x10) + +#endif /* TCC805X_OTPROM_H */ diff --git a/core/arch/arm/plat-telechips/tcc805x/platform_config.h b/core/arch/arm/plat-telechips/tcc805x/platform_config.h new file mode 100644 index 00000000000..fd2e2a85ce6 --- /dev/null +++ b/core/arch/arm/plat-telechips/tcc805x/platform_config.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#ifndef PLATFORM_CONFIG_H +#define PLATFORM_CONFIG_H + +#include +#include + +/* Make stacks aligned to data cache line length */ +#define STACK_ALIGNMENT 64 + +/* Peripherals */ +#define TCC_IO_BASE U(0x10000000) +#define TCC_IO_SIZE U(0x10000000) + +/* GIC */ +#define GICD_BASE U(0x17301000) +#define GICC_BASE U(0x17302000) + +/* Console */ +#define CONSOLE_UART_BASE U(0x16600000) +#define CONSOLE_UART_CLK_IN_HZ 24000000 +#define CONSOLE_BAUDRATE 115200 + +/* OTP */ +#define OTP_CTRL_BASE U(0x19101000) +#define OTP_CMD_BASE U(0xE0004000) + +/* TZC Cfg */ +#define TZC_BASE U(0xE8300000) +#define TZC_SIZE U(0x00100000) +#define TZC_OMC_BASE (TZC_BASE + U(0x80000)) +#define TZC_OMC_FILTERS U(4) +#define TZC_OMC_FILTER_OFFS U(0x10000) +#define TZC_OMC_INT_0 (U(231) + U(32)) +#define TZC_OMC_INT_1 (U(233) + U(32)) +#define TZC_OMC_INT_2 (U(235) + U(32)) +#define TZC_OMC_INT_3 (U(237) + U(32)) +#define TZC_TEEOS_REGION_NUM U(1) + +/* DRAM Info */ +#define DRAM0_BASE U(0x20000000) +#define DRAM0_SIZE U(0xA0000000) /* 2.5 GiB */ +#define DRAM1_BASE U(0x1A0000000) +#define DRAM1_SIZE U(0x60000000) /* 1.5 GiB */ + +#endif /*PLATFORM_CONFIG_H*/ diff --git a/core/drivers/openedges_omc.c b/core/drivers/openedges_omc.c new file mode 100644 index 00000000000..53a524fc19c --- /dev/null +++ b/core/drivers/openedges_omc.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2024, Telechips Inc. + * + * Driver for the Orbit Memory Controller. + * https://www.openedges.com/memorycontroller + */ + +#include +#include +#include +#include +#include +#include + +#define ACTION_OFF U(0x1004) + +#define INT_STATUS U(0x1010) +#define INT_CLEAR U(0x1014) +#define FAIL_ADDRESS_LOW_OFF U(0x1020) +#define FAIL_ADDRESS_HIGH_OFF U(0x1024) +#define FAIL_CONTROL_OFF U(0x1028) +#define FAIL_ID_OFF U(0x102c) +#define FAIL_DIRECTION_OFF(d) (U(0x20) * (d)) + +#define REGION_COUNT U(17) +#define REGION_BASE_LOW_OFF U(0x1100) +#define REGION_BASE_HIGH_OFF U(0x1104) +#define REGION_TOP_LOW_OFF U(0x1108) +#define REGION_TOP_HIGH_OFF U(0x110c) +#define REGION_ATTRIBUTES_OFF U(0x1110) +#define REGION_ID_ACCESS_OFF U(0x1114) +#define REGION_NUM_OFF(region) (U(0x20) * (region)) + +#define ADDRESS_CTRL0_OFF U(0x1f00) +#define ADDRESS_CTRL1_OFF U(0x1f04) +#define REGION0_START_OFF U(0x1f10) +#define REGION0_END_OFF U(0x1f14) +#define REGION0_CFG_OFF U(0x1f18) +#define REGION1_START_OFF U(0x1f20) +#define REGION1_END_OFF U(0x1f24) +#define REGION1_CFG_OFF U(0x1f28) +#define CHIP0_SIZE_OFF U(0x1f30) +#define CHIP1_SIZE_OFF U(0x1f34) + +#define INT_TYPE_READ U(0) +#define INT_TYPE_WRITE U(1) +#define INT_TYPE_MAX U(2) + +#define INT_STATUS_OVERLAP BIT(16) +#define INT_STATUS_OVERRUN BIT(8) +#define INT_STATUS_STATUS BIT(0) +#define INT_STATUS_MASK (INT_STATUS_OVERLAP | INT_STATUS_OVERRUN | \ + INT_STATUS_STATUS) + +#define INT_CLEAR_CLEAR_SHIFT U(0) +#define INT_CLEAR_CLEAR_MASK U(0x1) + +#define FAIL_CONTROL_NONSECURE BIT(21) +#define FAIL_CONTROL_PRIVILEGED BIT(20) + +#define FAIL_ID_AID_SHIFT U(8) +#define FAIL_ID_AID_MASK GENMASK_32(27, 8) +#define FAIL_ID_MID_SHIFT U(0) +#define FAIL_ID_MID_MASK GENMASK_32(7, 0) + +#define REG_ATTR_S_WR_EN BIT(31) +#define REG_ATTR_S_RD_EN BIT(30) +#define REG_ATTR_FILTER_EN BIT(0) + +struct omc_instance { + vaddr_t base; + uint32_t size; + uint8_t num_filters; +}; + +static struct omc_instance tzc; + +static void omc_write32(uint8_t filter, uint32_t offs, uint32_t val) +{ + vaddr_t filter_offs = filter * tzc.size; + + io_write32(tzc.base + filter_offs + offs, val); +} + +static uint32_t omc_read32(uint8_t filter, uint32_t offs) +{ + vaddr_t filter_offs = filter * tzc.size; + + return io_read32(tzc.base + filter_offs + offs); +} + +static void omc_write64(uint8_t filter, uint32_t offs, uint64_t val) +{ + vaddr_t filter_offs = filter * tzc.size; + + io_write64(tzc.base + filter_offs + offs, val); +} + +static uint64_t omc_read64(uint8_t filter, uint32_t offs) +{ + vaddr_t filter_offs = filter * tzc.size; + + return io_read64(tzc.base + filter_offs + offs); +} + +static void omc_write_region_base(uint8_t filter, uint32_t region, uint64_t val) +{ + omc_write64(filter, REGION_BASE_LOW_OFF + REGION_NUM_OFF(region), val); +} + +static void omc_write_region_top(uint8_t filter, uint32_t region, uint64_t val) +{ + omc_write64(filter, REGION_TOP_LOW_OFF + REGION_NUM_OFF(region), val); +} + +static void omc_write_region_attributes(uint8_t filter, uint32_t region, + uint32_t val) +{ + omc_write32(filter, REGION_ATTRIBUTES_OFF + REGION_NUM_OFF(region), + val); +} + +static void omc_write_region_id_access(uint8_t filter, uint32_t region, + uint32_t val) +{ + omc_write32(filter, REGION_ID_ACCESS_OFF + REGION_NUM_OFF(region), val); +} + +static uint64_t omc_read_start_address(uint8_t filter) +{ + return SHIFT_U64(omc_read32(filter, REGION0_START_OFF), 8); +} + +void omc_init(vaddr_t base, uint32_t size, uint8_t num) +{ + assert(base); + + tzc.base = base; + tzc.size = size; + tzc.num_filters = num; +} + +void omc_configure_region(uint8_t region, const struct omc_region_config *cfg) +{ + uint8_t filter = 0; + uint32_t attr = 0; + uint64_t start_addr = 0; + + if (!tzc.base) + panic("tzc.base is not registered"); + else if (!cfg) + panic("cfg is null"); + else if (cfg->filters >> tzc.num_filters) + panic("cfg->filters is overflowed"); + else if (region >= REGION_COUNT) + panic("region is overflowed"); + else if ((cfg->base | (cfg->top + 1)) & 0xFFF) + panic("region base or (top + 1) is not 4KB aligned"); + + for (filter = 0; filter < tzc.num_filters; filter++) { + if (cfg->flags & OMC_FLAG_RELATIVE_ADDR) + start_addr = omc_read_start_address(filter); + else + start_addr = 0; + + omc_write_region_base(filter, region, start_addr + cfg->base); + omc_write_region_top(filter, region, start_addr + cfg->top); + + /* Assign the region to a filter and set secure attributes */ + attr = REG_ATTR_S_WR_EN | REG_ATTR_S_RD_EN; + if (cfg->filters & BIT(filter)) + attr |= REG_ATTR_FILTER_EN; + omc_write_region_attributes(filter, region, attr); + + omc_write_region_id_access(filter, region, + cfg->ns_device_access); + } +} + +void omc_set_action(enum omc_action action) +{ + uint8_t filter = 0; + + if (!tzc.base) + panic("tzc.base is null"); + + for (filter = 0; filter < tzc.num_filters; filter++) + omc_write32(filter, ACTION_OFF, (uint32_t)action); +} + +void omc_fail_dump(uint8_t filter) +{ + uint64_t __maybe_unused addr = 0; + uint32_t status = 0; + uint32_t __maybe_unused ctrl = 0; + uint32_t __maybe_unused nsaid = 0; + uint32_t direction = 0; + + for (direction = INT_TYPE_READ; direction < INT_TYPE_MAX; direction++) { + status = omc_read32(filter, + INT_STATUS + FAIL_DIRECTION_OFF(direction)); + if (!(status & INT_STATUS_MASK)) + continue; + + if (status & INT_STATUS_OVERLAP) + EMSG("Overlap violation on filter %"PRIu8, filter); + + if (status & INT_STATUS_OVERRUN) + EMSG("Overrun violation on filter %"PRIu8, filter); + + if (status & INT_STATUS_STATUS) + EMSG("Permission violation on filter %"PRIu8, filter); + + ctrl = omc_read32(filter, FAIL_CONTROL_OFF + + FAIL_DIRECTION_OFF(direction)); + addr = omc_read64(filter, FAIL_ADDRESS_LOW_OFF + + FAIL_DIRECTION_OFF(direction)); + nsaid = omc_read32(filter, FAIL_ID_OFF + + FAIL_DIRECTION_OFF(direction)); + EMSG("Violation @%#"PRIx64 + ", %ssecure %sprivileged %s, MID %#"PRIx32", AID %#"PRIx32, + addr, + (ctrl & FAIL_CONTROL_NONSECURE) ? "non-" : "", + (ctrl & FAIL_CONTROL_PRIVILEGED) ? "" : "un", + (direction == INT_TYPE_WRITE) ? "write" : "read", + (nsaid & FAIL_ID_MID_MASK) >> FAIL_ID_MID_SHIFT, + (nsaid & FAIL_ID_AID_MASK) >> FAIL_ID_AID_SHIFT); + } +} + +void omc_int_clear(uint8_t filter) +{ + if (!tzc.base) + panic("tzc.base is null"); + + omc_write32(filter, INT_CLEAR, BIT(0)); +} diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk index 406593f3cd0..de822caf981 100644 --- a/core/drivers/sub.mk +++ b/core/drivers/sub.mk @@ -86,6 +86,7 @@ srcs-$(CFG_HISILICON_CRYPTO_DRIVER) += hisi_trng.c srcs-$(CFG_WIDEVINE_HUK) += widevine_huk.c srcs-$(CFG_SEMIHOSTING_CONSOLE) += semihosting_console.c srcs-$(CFG_FFA_CONSOLE) += ffa_console.c +srcs-$(CFG_OPENEDGES_OMC) += openedges_omc.c subdirs-y += crypto subdirs-$(CFG_BNXT_FW) += bnxt diff --git a/core/include/drivers/openedges_omc.h b/core/include/drivers/openedges_omc.h new file mode 100644 index 00000000000..d62c8f4a09e --- /dev/null +++ b/core/include/drivers/openedges_omc.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024, Telechips Inc. + */ + +#ifndef __DRIVERS_OPENEDGES_OMC_H +#define __DRIVERS_OPENEDGES_OMC_H + +#include +#include + +#define OMC_FLAG_RELATIVE_ADDR BIT(0) + +enum omc_action { + OMC_ACTION_NONE = 0, + OMC_ACTION_ERR, + OMC_ACTION_INT, + OMC_ACTION_ERR_INT +}; + +struct omc_region_config { + uint32_t filters; + uint64_t base; + uint64_t top; + uint32_t ns_device_access; + uint32_t flags; +}; + +void omc_init(vaddr_t base, uint32_t size, uint8_t num); +void omc_configure_region(uint8_t region, const struct omc_region_config *cfg); +void omc_set_action(enum omc_action action); + +void omc_fail_dump(uint8_t filter); +void omc_int_clear(uint8_t filter); + +#endif /* __DRIVERS_OPENEDGES_OMC_H */