diff --git a/changelog.yaml b/changelog.yaml index aebb792a7..ad9c9b5d3 100644 --- a/changelog.yaml +++ b/changelog.yaml @@ -504,6 +504,13 @@ subsections: - title: LS1088AQDS scope: ls1088aqds + - title: S32G274A + scope: s32g274a + + subsections: + - title: S32G274ARDB + scope: s32g274ardb + - title: QEMU scope: qemu diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst index 775333481..1f6892788 100644 --- a/docs/about/maintainers.rst +++ b/docs/about/maintainers.rst @@ -710,6 +710,15 @@ NXP SoC Part LS1088A and its platform port :|F|: plat/nxp/soc-ls1088a/ls1088ardb :|F|: plat/nxp/soc-ls1088a/ls1088aqds +NXP SoC Part S32G274A and its platform port +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:|M|: Ghennadi Procopciuc +:|G|: `gprocopciucnxp`_ +:|F|: docs/plat/s32g274a.rst +:|F|: drivers/nxp/console/linflex_console.S +:|F|: include/drivers/nxp/console/linflex.h +:|F|: plat/nxp/s32 + QEMU platform port ^^^^^^^^^^^^^^^^^^ :|M|: Jens Wiklander @@ -983,6 +992,7 @@ Conventional Changelog Extensions .. _davidvincze: https://github.com/davidvincze .. _etienne-lms: https://github.com/etienne-lms .. _glneo: https://github.com/glneo +.. _gprocopciucnxp: https://github.com/gprocopciucnxp .. _grandpaul: https://github.com/grandpaul .. _harrisonmutai-arm: https://github.com/harrisonmutai-arm .. _hilamirandakuzi1: https://github.com/hilamirandakuzi1 diff --git a/docs/plat/index.rst b/docs/plat/index.rst index 702726ee5..5c1ded03c 100644 --- a/docs/plat/index.rst +++ b/docs/plat/index.rst @@ -29,6 +29,7 @@ Platform Ports imx8m imx8ulp imx9 + s32g274a npcm845x nxp/index poplar diff --git a/docs/plat/s32g274a.rst b/docs/plat/s32g274a.rst new file mode 100644 index 000000000..3aa858e04 --- /dev/null +++ b/docs/plat/s32g274a.rst @@ -0,0 +1,99 @@ +NXP S32G274A +============ + +S32G2 is an NXP vehicle network processor combining ASIL D safety, hardware +security, high-performance real-time and application processing and network +acceleration. S32G2 supports the needs of new vehicle architectures: +service-oriented gateways, domain controllers, zonal processors, safety +processors and more. It is equipped with 4 Cortex-A53 cores operating at +1.0GHz. + +The TF-A includes support for one single S32G2-based board called S32G274ARDB2. +The S32G-VNP-RDB2 is a compact, highly optimized and integrated board +engineering for vehicle service-oriented gateway (SoG), domain control +applications, high-performance processing, safety and security applications. +More details about this board can be found at `s32g274ardb2`_. + +Boot Flow +--------- + +:: + + BootROM -> BL2 (SRAM) -> BL31 (SRAM) -> BL33 (DDR - TODO) + +.. warning:: + This boot flow is a preliminary version that will serve as a foundation for + upcoming S32G2 contributions. The execution will hang after the BL31 stage + due to U-Boot being deployed in SRAM instead of DDR. This issue will be + resolved with the addition of the DDR driver. + +Code Locations +-------------- + +- Downstream TF-A: + `link: `__ + +- Downstream U-Boot: + `link `__ + +- Downstream Linux: + `link `__ + +How to build +------------ + +The port currently available on the S32G274ARDB2 platform is in its initial +stage. This means that important drivers like DDR and storage are not yet +available. Consequently, the boot process depends on BootROM to load all TF-A +stages in SRAM. To create a bootable image, the script below should be used. +This script makes use of the ``mkimage`` tool, which is part of the U-Boot drop +for S32G274A SoCs. + +.. code:: bash + + #!/bin/bash -xe + TF_A="${TF_A:-`pwd`}" + UBOOT="${UBOOT:-${TF_A}/../u-boot}" + DEBUG="${DEBUG:-1}" + + FIP_BASE="0x34100000" + + if [ "${DEBUG}" -eq "1" ]; then + BUILD="debug" + else + BUILD="release" + fi + + BOOT_IMAGE="build/s32g274ardb2/${BUILD}/BOOT_IMAGE.bin" + BL2_BIN="build/s32g274ardb2/${BUILD}/bl2.bin" + FIP_BIN="build/s32g274ardb2/${BUILD}/fip.bin" + + # Generate bl2, bl31 and fip image + make -C "${TF_A}" -j9 'PLAT=s32g274ardb2' \ + BL33="${UBOOT}/u-boot-nodtb.bin" DEBUG="${DEBUG}" clean + make -C "${TF_A}" -j9 'PLAT=s32g274ardb2' \ + BL33="${UBOOT}/u-boot-nodtb.bin" DEBUG="${DEBUG}" bl2 + make -C "${TF_A}" -j9 'PLAT=s32g274ardb2' \ + BL33="${UBOOT}/u-boot-nodtb.bin" DEBUG="${DEBUG}" fip + + # Extract BL2 entry + BL2_START="0x$(poetry run memory -p s32g274ardb2 -b debug -f | \ + grep BL2 | awk -F'|' '{print $3}' | xargs)" + # BL2 bin file size in bytes + BL2_SIZE="$(stat -c "%s" "${BL2_BIN}")" + + # Pack bl2.bin and fip.bin by ensuring that the FIP image will start at FIP_BASE + cp -vf "${BL2_BIN}" "${BOOT_IMAGE}" + dd if="${FIP_BIN}" of="${BOOT_IMAGE}" seek="$((FIP_BASE - BL2_START))" bs=1 + + # Build a bootable image by appending the IVT + "${UBOOT}/tools/mkimage" \ + -a "${BL2_START}" \ + -e "${BL2_START}" \ + -T s32ccimage \ + -n "${UBOOT}/u-boot-s32.cfgout" \ + -d "${BOOT_IMAGE}" \ + fip.s32 + +.. _s32g2: https://www.nxp.com/products/processors-and-microcontrollers/s32-automotive-platform/s32g-vehicle-network-processors/s32g2-processors-for-vehicle-networking:S32G2 +.. _s32g274ardb2: https://www.nxp.com/design/design-center/designs/s32g2-vehicle-networking-reference-design:S32G-VNP-RDB2 diff --git a/drivers/nxp/console/console.mk b/drivers/nxp/console/console.mk index 6174650d1..5f3c6e349 100644 --- a/drivers/nxp/console/console.mk +++ b/drivers/nxp/console/console.mk @@ -1,5 +1,5 @@ # -# Copyright 2021 NXP +# Copyright 2021-2024 NXP # # SPDX-License-Identifier: BSD-3-Clause # @@ -27,9 +27,14 @@ else ifeq ($(CONSOLE), PL011) CONSOLE_SOURCES := drivers/arm/pl011/aarch64/pl011_console.S \ ${PLAT_DRIVERS_PATH}/console/console_pl011.c +else +ifeq ($(CONSOLE), LINFLEX) +CONSOLE_SOURCES := ${PLAT_DRIVERS_PATH}/console/linflex_console.S else $(error -> CONSOLE not set!) endif + +endif endif ifeq (${BL_COMM_CONSOLE_NEEDED},yes) diff --git a/drivers/nxp/console/linflex_console.S b/drivers/nxp/console/linflex_console.S new file mode 100644 index 000000000..abcbb594e --- /dev/null +++ b/drivers/nxp/console/linflex_console.S @@ -0,0 +1,259 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +#define LDIV_MULTIPLIER U(16) + +#define LINFLEX_LINCR1 (0x0) +#define LINCR1_INIT BIT_32(0) +#define LINCR1_MME BIT_32(4) + +#define LINFLEX_LINSR (0x8) +#define LINSR_LINS_INITMODE (0x00001000) +#define LINSR_LINS_MASK (0x0000F000) + +#define LINFLEX_UARTCR (0x10) +#define UARTCR_ROSE BIT_32(23) + +#define LINFLEX_UARTSR (0x14) +#define LINFLEX_LINIBRR (0x28) +#define LINFLEX_LINFBRR (0x24) +#define LINFLEX_BDRL (0x38) +#define LINFLEX_UARTPTO (0x50) + +#define UARTCR_UART BIT_32(0) +#define UARTCR_WL0 BIT_32(1) +#define UARTCR_PC0 BIT_32(3) +#define UARTCR_TXEN BIT_32(4) +#define UARTCR_RXEN BIT_32(5) +#define UARTCR_PC1 BIT_32(6) +#define UARTCR_TFBM BIT_32(8) +#define UARTCR_RFBM BIT_32(9) +#define UARTCR_OSR_SHIFT U(24) +#define UARTCR_OSR_WIDTH U(4) + +#define UARTSR_DTF BIT_32(1) + +/* + * "core" functions are low-level implementations that do not require + * writable memory and are thus safe to call in BL1 crash context. + */ +.globl console_linflex_core_init +.globl console_linflex_core_putc + +.globl console_linflex_register +.globl console_linflex_putc + +/** + * uint32_t get_ldiv_mult(uintptr_t baseaddr, uint32_t clock, + * uint32_t baud, console_t *console,); + * + * Clobber list : x0 - x6 + * Out x4: LDIV multiplier + */ +func get_ldiv_mult + ldr w4, [x0, LINFLEX_UARTCR] + mov w5, w4 + + /* Prepare choices in w5 and w6 */ + ubfx x5, x5, #UARTCR_OSR_SHIFT, #UARTCR_OSR_WIDTH + mov w6, #LDIV_MULTIPLIER + + and w4, w4, #UARTCR_ROSE + cmp w4, #0x0 + csel w4, w5, w6, ne + ret +endfunc get_ldiv_mult + +/* + * void linflex_set_brg(uintptr_t baseaddr, uint32_t clock + * uint32_t baud, console_t *console); + * + * Clobber list : x0 - x7, x13 + */ +func linflex_set_brg + mov x13, x30 + bl get_ldiv_mult + mov x30, x13 + + /* (x4) dividr = baudrate * ldiv_mult */ + mul x4, x4, x2 + /* (x5) divisr = clock rate */ + mov x5, x1 + /* (x6) ibr = divisr / dividr */ + udiv x6, x5, x4 + /* (x7) fbr = divisr % dividr */ + msub x7, x6, x4, x5 + /* fbr *= 16 / dividr */ + lsl x7, x7, #4 + udiv x7, x7, x4 + /* fbr &= 0xf */ + and w7, w7, #0xf + str w6, [x0, LINFLEX_LINIBRR] + str w7, [x0, LINFLEX_LINFBRR] + ret +endfunc linflex_set_brg + +/** + * int console_linflex_core_init(uintptr_t baseaddr, uint32_t clock, + * uint32_t baud); + * + * In: x0 - Linflex base address + * x1 - clock frequency + * x2 - baudrate + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x7, x13 - x14 + */ +func console_linflex_core_init + /* Set master mode and init mode */ + mov w4, #(LINCR1_INIT) + str w4, [x0, LINFLEX_LINCR1] + mov w4, #(LINCR1_MME | LINCR1_INIT) + str w4, [x0, LINFLEX_LINCR1] + + /* wait for init mode entry */ +wait_init_entry: + ldr w4, [x0, LINFLEX_LINSR] + and w4, w4, #LINSR_LINS_MASK + cmp w4, #LINSR_LINS_INITMODE + b.ne wait_init_entry + + /* Set UART bit */ + mov w4, #UARTCR_UART + str w4, [x0, LINFLEX_UARTCR] + + mov x14, x30 + bl linflex_set_brg + mov x30, x14 + + /* Set preset timeout register value. */ + mov w4, #0xf + str w4, [x0, LINFLEX_UARTPTO] + + /* 8-bit data, no parity, Tx/Rx enabled, UART mode */ + mov w4, #(UARTCR_PC1 | UARTCR_RXEN | UARTCR_TXEN | UARTCR_PC0 | \ + UARTCR_WL0 | UARTCR_UART | UARTCR_RFBM | UARTCR_TFBM) + str w4, [x0, LINFLEX_UARTCR] + + /* End init mode */ + ldr w4, [x0, LINFLEX_LINCR1] + bic w4, w4, #LINCR1_INIT + str w4, [x0, LINFLEX_LINCR1] + ret +endfunc console_linflex_core_init + +/** + * int console_linflex_register(uintptr_t baseaddr, uint32_t clock, + * uint32_t clock, uint32_t baud); + * + * Function to initialize and register the console. + * The caller needs to pass an empty console_linflex_t + * structure in which *MUST* be allocated in + * persistent memory (e.g. a global or static local + * variable, *NOT* on the stack). + * In: x0 - Linflex base address + * x1 - clock frequency + * x2 - baudrate + * x3 - pointer to empty console_t structure + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x7, x13 - x15 + */ +func console_linflex_register + mov x15, x30 + bl console_linflex_core_init + mov x30, x15 + + /* Populate the base address */ + str x0, [x3, #CONSOLE_T_BASE] + + mov x0, x3 + finish_console_register linflex, putc=1, getc=0, flush=0 +endfunc console_linflex_register + +/** + * int console_linflex_core_putc(int c, uintptr_t baseaddr); + + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x0 - x3 + */ +func console_linflex_core_putc + cbz x1, putc_error + + cmp w0, #'\n' + b.ne print_char + + /* Print '\r\n' for each '\n' */ + mov x0, #'\r' + mov x14, x30 + bl console_linflex_core_putc + mov x30, x14 + mov x0, #'\n' + +print_char: + ldr w2, [x1, LINFLEX_UARTCR] + and w2, w2, #UARTCR_TFBM + cmp w2, #0x0 + b.eq buffer_mode + +fifo_mode: + /* UART is in FIFO mode */ + ldr w2, [x1, LINFLEX_UARTSR] + and w2, w2, #UARTSR_DTF + cmp w2, #0 + b.ne fifo_mode + + strb w0, [x1, LINFLEX_BDRL] + b no_error + +buffer_mode: + strb w0, [x1, LINFLEX_BDRL] + +buffer_loop: + ldr w2, [x1, LINFLEX_UARTSR] + and w3, w2, #UARTSR_DTF + cmp w3, #0 + b.eq buffer_loop + + /** + * In Buffer Mode the DTFTFF bit of UARTSR register + * has to be set in software + */ + mov w2, #UARTSR_DTF + str w2, [x1, LINFLEX_UARTSR] + +no_error: + mov x0, #0 + ret + +putc_error: + mov x0, #-EINVAL + ret +endfunc console_linflex_core_putc + +/** + * int console_linflex_putc(int c, console_t *console); + * + * Function to output a character over the console. It + * returns the character printed on success or -EINVAL on error. + * In : w0 - character to be printed + * x1 - pointer to console_t struct + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x0 - x3, x15 + */ +func console_linflex_putc + cbz x1, putc_error + ldr x1, [x1, #CONSOLE_T_BASE] + + b console_linflex_core_putc +puct_error: + mov x0, #-EINVAL + ret +endfunc console_linflex_putc diff --git a/include/drivers/nxp/console/linflex.h b/include/drivers/nxp/console/linflex.h new file mode 100644 index 000000000..2b4e0d712 --- /dev/null +++ b/include/drivers/nxp/console/linflex.h @@ -0,0 +1,18 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LINFLEX_H +#define LINFLEX_H + +#ifndef __ASSEMBLER__ +#include + +int console_linflex_core_init(uintptr_t baseaddr, uint32_t clock, + uint32_t baud); +int console_linflex_register(uintptr_t baseaddr, uint32_t clock, + uint32_t baud, console_t *console); +#endif + +#endif /* LINFLEX_H */ diff --git a/plat/nxp/s32/s32g274ardb2/include/plat_console.h b/plat/nxp/s32/s32g274ardb2/include/plat_console.h new file mode 100644 index 000000000..43c2bfd85 --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/include/plat_console.h @@ -0,0 +1,12 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_CONSOLE_H +#define PLAT_CONSOLE_H + +void console_s32g2_register(void); + +#endif diff --git a/plat/nxp/s32/s32g274ardb2/include/plat_helpers.h b/plat/nxp/s32/s32g274ardb2/include/plat_helpers.h new file mode 100644 index 000000000..18582ec49 --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/include/plat_helpers.h @@ -0,0 +1,12 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_HELPERS_H +#define PLAT_HELPERS_H + +unsigned int s32g2_core_pos_by_mpidr(u_register_t mpidr); + +#endif /* PLAT_HELPERS_H */ diff --git a/plat/nxp/s32/s32g274ardb2/include/plat_io_storage.h b/plat/nxp/s32/s32g274ardb2/include/plat_io_storage.h new file mode 100644 index 000000000..ea0130091 --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/include/plat_io_storage.h @@ -0,0 +1,12 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_IO_STORAGE_H +#define PLAT_IO_STORAGE_H + +void plat_s32g2_io_setup(void); + +#endif diff --git a/plat/nxp/s32/s32g274ardb2/include/plat_macros.S b/plat/nxp/s32/s32g274ardb2/include/plat_macros.S new file mode 100644 index 000000000..8f0c4726d --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/include/plat_macros.S @@ -0,0 +1,22 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + +/* --------------------------------------------- + * The below required platform porting macro + * prints out relevant GIC and CCI registers + * whenever an unhandled exception is taken in + * BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ +.macro plat_crash_print_regs +.endm + +#endif /* PLAT_MACROS_S */ + diff --git a/plat/nxp/s32/s32g274ardb2/include/platform_def.h b/plat/nxp/s32/s32g274ardb2/include/platform_def.h new file mode 100644 index 000000000..bdfeee2ad --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/include/platform_def.h @@ -0,0 +1,78 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include + +#define PLATFORM_STACK_SIZE U(0x1000) + +/* Caches */ +#define CACHE_WRITEBACK_SHIFT U(6) +#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) + +/* CPU Topology */ +#define PLATFORM_CORE_COUNT U(4) +#define PLATFORM_SYSTEM_COUNT U(1) +#define PLATFORM_CLUSTER_COUNT U(2) +#define PLATFORM_PRIMARY_CPU U(0) +#define PLATFORM_MPIDR_CPU_MASK_BITS U(1) +#define PLATFORM_MAX_CPUS_PER_CLUSTER U(2) + +/* Power Domains */ +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_SYSTEM_COUNT + \ + PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 +#define PLAT_MAX_OFF_STATE U(2) +#define PLAT_MAX_RET_STATE U(1) +#define PLAT_MAX_PWR_LVL_STATES U(2) + +/* BL2 stage */ +#define BL2_BASE UL(0x34078000) +#define BL2_LIMIT UL(0x34100000) + +/* BL31 stage */ +#define BL31_BASE UL(0x34200000) +#define BL31_LIMIT UL(0x34300000) + +/* It is a dummy value for now, given the missing DDR */ +#define BL33_BASE UL(0x34500000) +#define BL33_LIMIT UL(0x345FF000) + +#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 36) +/* We'll be doing a 1:1 mapping anyway */ +#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 36) + +#define MAX_MMAP_REGIONS U(8) +#define MAX_XLAT_TABLES U(32) + +/* Console settings */ +#define UART_BASE UL(0x401C8000) +#define UART_BAUDRATE U(115200) +/* FIRC clock */ +#define UART_CLOCK_HZ U(48000000) + +#define S32G_FIP_BASE UL(0x34100000) +#define S32G_FIP_SIZE UL(0x100000) + +#define MAX_IO_HANDLES U(2) +#define MAX_IO_DEVICES U(2) + +/* GIC settings */ +#define S32G_GIC_BASE UL(0x50800000) +#define PLAT_GICD_BASE S32G_GIC_BASE +#define PLAT_GICR_BASE (S32G_GIC_BASE + UL(0x80000)) + +/* Generic timer frequency; this goes directly into CNTFRQ_EL0. + * Its end-value is 5MHz; this is based on the assumption that + * GPR00[CA53_COUNTER_CLK_DIV_VAL] contains the reset value of 0x7, hence + * producing a divider value of 8, applied to the FXOSC frequency of 40MHz. + */ +#define COUNTER_FREQUENCY U(5000000) + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c b/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c new file mode 100644 index 000000000..f265d956f --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c @@ -0,0 +1,62 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#define SIUL2_PC09_MSCR UL(0x4009C2E4) +#define SIUL2_PC10_MSCR UL(0x4009C2E8) +#define SIUL2_PC10_LIN0_IMCR UL(0x4009CA40) + +#define LIN0_TX_MSCR_CFG U(0x00214001) +#define LIN0_RX_MSCR_CFG U(0x00094000) +#define LIN0_RX_IMCR_CFG U(0x00000002) + +struct bl_load_info *plat_get_bl_image_load_info(void) +{ + return get_bl_load_info_from_mem_params_desc(); +} + +struct bl_params *plat_get_next_bl_params(void) +{ + return get_next_bl_params_from_mem_params_desc(); +} + +void plat_flush_next_bl_params(void) +{ + flush_bl_params_desc(); +} + +void bl2_platform_setup(void) +{ +} + +static void linflex_config_pinctrl(void) +{ + /* set PC09 - MSCR[41] - for UART0 TXD */ + mmio_write_32(SIUL2_PC09_MSCR, LIN0_TX_MSCR_CFG); + /* set PC10 - MSCR[42] - for UART0 RXD */ + mmio_write_32(SIUL2_PC10_MSCR, LIN0_RX_MSCR_CFG); + /* set PC10 - MSCR[512]/IMCR[0] - for UART0 RXD */ + mmio_write_32(SIUL2_PC10_LIN0_IMCR, LIN0_RX_IMCR_CFG); +} + +void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + linflex_config_pinctrl(); + console_s32g2_register(); + + plat_s32g2_io_setup(); +} + +void bl2_el3_plat_arch_setup(void) +{ +} + diff --git a/plat/nxp/s32/s32g274ardb2/plat_bl2_image_desc.c b/plat/nxp/s32/s32g274ardb2/plat_bl2_image_desc.c new file mode 100644 index 000000000..1fc77941e --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/plat_bl2_image_desc.c @@ -0,0 +1,41 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +static bl_mem_params_node_t bl2_mem_params_descs[] = { + { + .image_id = BL31_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, + entry_point_info_t, + SECURE | EXECUTABLE | EP_FIRST_EXE), + .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS), + .ep_info.pc = BL31_BASE, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, + image_info_t, IMAGE_ATTRIB_PLAT_SETUP), + .image_info.image_max_size = BL31_LIMIT - BL31_BASE, + .image_info.image_base = BL31_BASE, + .next_handoff_image_id = BL33_IMAGE_ID, + }, + { + .image_id = BL33_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, + entry_point_info_t, + NON_SECURE | EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, + image_info_t, 0), + .image_info.image_max_size = BL33_LIMIT - BL33_BASE, + .image_info.image_base = BL33_BASE, + .next_handoff_image_id = INVALID_IMAGE_ID, + }, +}; + +REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) diff --git a/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c b/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c new file mode 100644 index 000000000..03bf35cc1 --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/plat_bl31_setup.c @@ -0,0 +1,75 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +static entry_point_info_t bl33_image_ep_info; + +static unsigned int s32g2_mpidr_to_core_pos(unsigned long mpidr); + +static uint32_t get_spsr_for_bl33_entry(void) +{ + unsigned long mode = MODE_EL1; + uint32_t spsr; + + spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + + return spsr; +} + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + console_s32g2_register(); + + SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); + bl33_image_ep_info.pc = BL33_BASE; + bl33_image_ep_info.spsr = get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); +} + +void bl31_plat_arch_setup(void) +{ +} + +struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + return &bl33_image_ep_info; +} + +void bl31_platform_setup(void) +{ + static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + static gicv3_driver_data_t plat_gic_data = { + .gicd_base = PLAT_GICD_BASE, + .gicr_base = PLAT_GICR_BASE, + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = rdistif_base_addrs, + .mpidr_to_core_pos = s32g2_mpidr_to_core_pos, + }; + + unsigned int pos = plat_my_core_pos(); + + gicv3_driver_init(&plat_gic_data); + gicv3_distif_init(); + gicv3_rdistif_init(pos); + gicv3_cpuif_enable(pos); +} + +static unsigned int s32g2_mpidr_to_core_pos(unsigned long mpidr) +{ + int core; + + core = plat_core_pos_by_mpidr(mpidr); + if (core < 0) { + return 0; + } + + return (unsigned int)core; +} + diff --git a/plat/nxp/s32/s32g274ardb2/plat_console.c b/plat/nxp/s32/s32g274ardb2/plat_console.c new file mode 100644 index 000000000..27cae129e --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/plat_console.c @@ -0,0 +1,28 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +void console_s32g2_register(void) +{ + static console_t s32g2_console; + int ret; + + (void)memset(&s32g2_console, 0, sizeof(s32g2_console)); + + ret = console_linflex_register(UART_BASE, UART_CLOCK_HZ, + UART_BAUDRATE, &s32g2_console); + if (ret == 0) { + panic(); + } + + console_set_scope(&s32g2_console, + CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | + CONSOLE_FLAG_TRANSLATE_CRLF); +} diff --git a/plat/nxp/s32/s32g274ardb2/plat_helpers.S b/plat/nxp/s32/s32g274ardb2/plat_helpers.S new file mode 100644 index 000000000..193c884da --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/plat_helpers.S @@ -0,0 +1,130 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#define S32G_NCORE_CAIU0_BASE_ADDR UL(0x50400000) +#define S32G_NCORE_CAIUTC_OFF U(0x0) +#define S32G_NCORE_CAIUTC_ISOLEN_SHIFT U(1) + +.globl plat_crash_console_flush +.globl plat_crash_console_init +.globl plat_crash_console_putc +.globl plat_is_my_cpu_primary +.globl plat_my_core_pos +.globl plat_reset_handler +.globl plat_secondary_cold_boot_setup +.globl platform_mem_init +.globl s32g2_core_pos_by_mpidr + +/* int plat_crash_console_init(void); */ +func plat_crash_console_init + mov_imm x0, UART_BASE + mov_imm x1, UART_CLOCK_HZ + mov_imm x2, UART_BAUDRATE + b console_linflex_core_init +endfunc plat_crash_console_init + +/* int plat_crash_console_putc(int); */ +func plat_crash_console_putc + mov_imm x1, UART_BASE + b console_linflex_core_putc + ret +endfunc plat_crash_console_putc + +/* void plat_crash_console_flush(void); */ +func plat_crash_console_flush + ret +endfunc plat_crash_console_flush + +/** + * unsigned int s32g2_core_pos_by_mpidr(u_register_t mpidr); + * + * In: x0 - MPIDR_EL1 + * Out: x0 + * Clobber list: x0, x1 + */ +func s32g2_core_pos_by_mpidr + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + lsr x0, x0, #MPIDR_AFF1_SHIFT + add x0, x1, x0, lsl #PLATFORM_MPIDR_CPU_MASK_BITS + ret +endfunc s32g2_core_pos_by_mpidr + +/** + * unsigned int plat_my_core_pos(void); + * + * Out: x0 + * Clobber list: x0, x1, x8 + */ +func plat_my_core_pos + mov x8, x30 + mrs x0, mpidr_el1 + bl s32g2_core_pos_by_mpidr + mov x30, x8 + ret +endfunc plat_my_core_pos + +/** + * unsigned int plat_is_my_cpu_primary(void); + * + * Clobber list: x0, x1, x7, x8 + */ +func plat_is_my_cpu_primary + mov x7, x30 + bl plat_my_core_pos + cmp x0, #PLATFORM_PRIMARY_CPU + cset x0, eq + mov x30, x7 + ret +endfunc plat_is_my_cpu_primary + + +/** + * void plat_secondary_cold_boot_setup (void); + */ +func plat_secondary_cold_boot_setup + ret +endfunc plat_secondary_cold_boot_setup + +/** + * void plat_reset_handler(void); + * + * Set the CAIUTC[IsolEn] bit for the primary A53 cluster. + * This is so cache invalidate operations from the early TF-A boot code + * won't cause Ncore to crash. + * + * Clobber list: x0, x1, x2 + */ +func plat_reset_handler + mov x0, #S32G_NCORE_CAIU0_BASE_ADDR + ldr w1, [x0, #S32G_NCORE_CAIUTC_OFF] + movz w2, #1 + lsl w2, w2, #S32G_NCORE_CAIUTC_ISOLEN_SHIFT + orr w1, w1, w2 + str w1, [x0, #S32G_NCORE_CAIUTC_OFF] + ret +endfunc plat_reset_handler + +/* void platform_mem_init(void); */ +func platform_mem_init + mov x10, x30 + mov x0, #BL31_BASE + mov x1, #(BL31_LIMIT & 0xFFFFU) + movk x1, #(BL31_LIMIT >> 16), lsl #16 + sub x1, x1, x0 + bl zeromem + mov x0, #BL33_BASE + mov x1, #(BL33_LIMIT & 0xFFFFU) + movk x1, #(BL33_LIMIT >> 16), lsl #16 + sub x1, x1, x0 + bl zeromem + mov x30, x10 + ret +endfunc platform_mem_init + diff --git a/plat/nxp/s32/s32g274ardb2/plat_io_storage.c b/plat/nxp/s32/s32g274ardb2/plat_io_storage.c new file mode 100644 index 000000000..db6bcc51d --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/plat_io_storage.c @@ -0,0 +1,135 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include +#include +#include + +#include + +struct plat_io_policy { + uintptr_t *dev_handle; + uintptr_t image_spec; + int (*check)(const uintptr_t spec); +}; + +static int open_memmap(const uintptr_t spec); +static int open_fip(const uintptr_t spec); + +static uintptr_t fip_dev_handle; + +static uintptr_t memmap_dev_handle; + +static int open_memmap(const uintptr_t spec) +{ + uintptr_t temp_handle = 0U; + int result; + + result = io_dev_init(memmap_dev_handle, (uintptr_t)0); + if (result != 0) { + return result; + } + + result = io_open(memmap_dev_handle, spec, &temp_handle); + if (result == 0) { + (void)io_close(temp_handle); + } + + return result; +} + +static int open_fip(const uintptr_t spec) +{ + uintptr_t temp_handle = 0U; + int result; + + /* See if a Firmware Image Package is available */ + result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); + if (result != 0) { + return result; + } + + result = io_open(fip_dev_handle, spec, &temp_handle); + if (result == 0) { + (void)io_close(temp_handle); + } + + return result; +} + +void plat_s32g2_io_setup(void) +{ + static const io_dev_connector_t *memmap_dev_con; + static const io_dev_connector_t *fip_dev_con; + + int result __unused; + + result = register_io_dev_memmap(&memmap_dev_con); + assert(result == 0); + + result = io_dev_open(memmap_dev_con, (uintptr_t)0, + &memmap_dev_handle); + assert(result == 0); + + result = register_io_dev_fip(&fip_dev_con); + assert(result == 0); + + result = io_dev_open(fip_dev_con, (uintptr_t)0, + &fip_dev_handle); + assert(result == 0); +} + +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + static const io_block_spec_t fip_block_spec = { + .offset = S32G_FIP_BASE, + .length = S32G_FIP_SIZE, + }; + + static const io_uuid_spec_t bl31_uuid_spec = { + .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, + }; + + static const io_uuid_spec_t bl33_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, + }; + + static const struct plat_io_policy policies[BL33_IMAGE_ID + 1] = { + [FIP_IMAGE_ID] = { + .dev_handle = &memmap_dev_handle, + .image_spec = (uintptr_t)&fip_block_spec, + .check = open_memmap, + }, + [BL31_IMAGE_ID] = { + .dev_handle = &fip_dev_handle, + .image_spec = (uintptr_t)&bl31_uuid_spec, + .check = open_fip, + }, + [BL33_IMAGE_ID] = { + .dev_handle = &fip_dev_handle, + .image_spec = (uintptr_t)&bl33_uuid_spec, + .check = open_fip, + }, + }; + const struct plat_io_policy *policy; + int result; + + assert(image_id < ARRAY_SIZE(policies)); + + policy = &policies[image_id]; + result = policy->check(policy->image_spec); + assert(result == 0); + + *image_spec = policy->image_spec; + *dev_handle = *policy->dev_handle; + + return result; +} diff --git a/plat/nxp/s32/s32g274ardb2/platform.mk b/plat/nxp/s32/s32g274ardb2/platform.mk new file mode 100644 index 000000000..ee1507e5d --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/platform.mk @@ -0,0 +1,65 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include drivers/arm/gic/v3/gicv3.mk +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_DRIVERS_PATH := drivers/nxp +PLAT_COMMON_PATH := plat/nxp/common +PLAT_S32G274ARDB2 := plat/nxp/s32/s32g274ardb2 + +CONSOLE := LINFLEX + +include ${PLAT_COMMON_PATH}/plat_make_helper/plat_build_macros.mk + +PLAT_INCLUDES = \ + -I${PLAT_S32G274ARDB2}/include + +PROGRAMMABLE_RESET_ADDRESS := 1 + +COLD_BOOT_SINGLE_CPU := 0 + +ENABLE_SVE_FOR_NS := 0 + +RESET_TO_BL2 := 1 + +INIT_UNUSED_NS_EL2 := 1 + +ERRATA_A53_855873 := 1 +ERRATA_A53_836870 := 1 +ERRATA_A53_1530924 := 1 +ERRATA_SPECULATIVE_AT := 1 + +# Selecting Drivers for SoC +$(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM)) + +include ${PLAT_DRIVERS_PATH}/drivers.mk + + +BL_COMMON_SOURCES += \ + ${PLAT_S32G274ARDB2}/plat_console.c \ + ${PLAT_S32G274ARDB2}/plat_helpers.S \ + +BL2_SOURCES += \ + ${BL_COMMON_SOURCES} \ + ${PLAT_S32G274ARDB2}/plat_bl2_el3_setup.c \ + ${PLAT_S32G274ARDB2}/plat_bl2_image_desc.c \ + ${PLAT_S32G274ARDB2}/plat_io_storage.c \ + common/desc_image_load.c \ + drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_storage.c \ + lib/cpus/aarch64/cortex_a53.S \ + +BL31_SOURCES += \ + ${GICV3_SOURCES} \ + ${PLAT_S32G274ARDB2}/plat_bl31_setup.c \ + ${PLAT_S32G274ARDB2}/s32g2_psci.c \ + ${PLAT_S32G274ARDB2}/s32g2_soc.c \ + ${XLAT_TABLES_LIB_SRCS} \ + lib/cpus/aarch64/cortex_a53.S \ + plat/common/plat_gicv3.c \ + plat/common/plat_psci_common.c \ diff --git a/plat/nxp/s32/s32g274ardb2/s32g2_psci.c b/plat/nxp/s32/s32g274ardb2/s32g2_psci.c new file mode 100644 index 000000000..2d02d94be --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/s32g2_psci.c @@ -0,0 +1,20 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + static const plat_psci_ops_t s32g2_psci_ops = { + }; + + *psci_ops = &s32g2_psci_ops; + + return 0; +} + diff --git a/plat/nxp/s32/s32g274ardb2/s32g2_soc.c b/plat/nxp/s32/s32g274ardb2/s32g2_soc.c new file mode 100644 index 000000000..000135239 --- /dev/null +++ b/plat/nxp/s32/s32g274ardb2/s32g2_soc.c @@ -0,0 +1,52 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + static const unsigned char s32g_power_domain_tree_desc[] = { + PLATFORM_SYSTEM_COUNT, + PLATFORM_CLUSTER_COUNT, + PLATFORM_CORE_COUNT / U(2), + PLATFORM_CORE_COUNT / U(2), + }; + + return s32g_power_domain_tree_desc; +} + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int cluster_id, cpu_id, core_id; + u_register_t mpidr_priv = mpidr; + + mpidr_priv &= MPIDR_AFFINITY_MASK; + + if ((mpidr_priv & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0) { + return -1; + } + + cluster_id = MPIDR_AFFLVL1_VAL(mpidr_priv); + cpu_id = MPIDR_AFFLVL0_VAL(mpidr_priv); + + if ((cluster_id >= PLATFORM_CLUSTER_COUNT) || + (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)) { + return -1; + } + + core_id = s32g2_core_pos_by_mpidr(mpidr_priv); + if (core_id >= PLATFORM_CORE_COUNT) { + return -1; + } + + return (int)core_id; +} + +unsigned int plat_get_syscnt_freq2(void) +{ + return COUNTER_FREQUENCY; +}