diff --git a/arch.mk b/arch.mk index de3a68137..0eb12ff4f 100644 --- a/arch.mk +++ b/arch.mk @@ -62,13 +62,39 @@ endif ## ARM Cortex-A ifeq ($(ARCH),AARCH64) CROSS_COMPILE?=aarch64-none-elf- - CFLAGS+=-DARCH_AARCH64 -march=armv8-a + CFLAGS+=-DARCH_AARCH64 OBJS+=src/boot_aarch64.o src/boot_aarch64_start.o - CFLAGS+=-DNO_QNX + + ifeq ($(TARGET),nxp_ls1028a) + ARCH_FLAGS=-mcpu=cortex-a72+crypto -march=armv8-a+crypto -mtune=cortex-a72 + CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A72 + + CFLAGS +=-ffunction-sections -fdata-sections + LDFLAGS+=-Wl,--gc-sections + + ifeq ($(DEBUG_UART),0) + CFLAGS+=-fno-builtin-printf + endif + + SPI_TARGET=nxp + else + # By default disable ARM ASM for other targets + NO_ARM_ASM?=1 + endif + ifeq ($(SPMATH),1) MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_arm64.o endif + ifeq ($(NO_ARM_ASM),0) + ARCH_FLAGS=-mstrict-align + CFLAGS+=$(ARCH_FLAGS) -DWOLFSSL_ARMASM -DWOLFSSL_ARMASM_INLINE -DWC_HASH_DATA_ALIGNMENT=8 + WOLFCRYPT_OBJS += lib/wolfssl/wolfcrypt/src/port/arm/armv8-sha256.o \ + lib/wolfssl/wolfcrypt/src/port/arm/armv8-sha512.o \ + lib/wolfssl/wolfcrypt/src/port/arm/armv8-aes.o \ + lib/wolfssl/wolfcrypt/src/port/arm/armv8-sha512-asm_c.o \ + lib/wolfssl/wolfcrypt/src/port/arm/armv8-sha3-asm_c.o + endif endif ## ARM Cortex-M @@ -202,11 +228,13 @@ ifeq ($(CORTEX_A5),1) MATH_OBJS+=./lib/wolfssl/wolfcrypt/src/sp_c32.o else MATH_OBJS+=./lib/wolfssl/wolfcrypt/src/sp_arm32.o - OBJS+=./lib/wolfssl/wolfcrypt/src/port/arm/armv8-sha256.o - OBJS+=./lib/wolfssl/wolfcrypt/src/port/arm/armv8-32-sha256-asm.o - OBJS+=./lib/wolfssl/wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.o - CFLAGS+=-DWOLFSSL_SP_ARM32_ASM -DWOLFSSL_ARMASM -DWOLFSSL_ARMASM_NO_HW_CRYPTO \ - -DWOLFSSL_ARM_ARCH=7 -DWOLFSSL_ARMASM_INLINE -DWOLFSSL_ARMASM_NO_NEON + ifneq ($(NO_ARM_ASM),1) + OBJS+=./lib/wolfssl/wolfcrypt/src/port/arm/armv8-sha256.o + OBJS+=./lib/wolfssl/wolfcrypt/src/port/arm/armv8-32-sha256-asm.o + OBJS+=./lib/wolfssl/wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.o + CFLAGS+=-DWOLFSSL_SP_ARM32_ASM -DWOLFSSL_ARMASM -DWOLFSSL_ARMASM_NO_HW_CRYPTO \ + -DWOLFSSL_ARM_ARCH=7 -DWOLFSSL_ARMASM_INLINE -DWOLFSSL_ARMASM_NO_NEON + endif endif else # All others use boot_arm.o @@ -230,8 +258,7 @@ else CORTEXM_ARM_EXTRA_CFLAGS+=-DWOLFSSL_ARMASM -DWOLFSSL_ARMASM_NO_HW_CRYPTO \ - -DWOLFSSL_ARMASM_NO_NEON - CORTEXM_ARM_EXTRA_CFLAGS+=-DWOLFSSL_ARMASM_THUMB2 + -DWOLFSSL_ARMASM_NO_NEON -DWOLFSSL_ARMASM_THUMB2 endif ifeq ($(CORTEX_M33),1) CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33 diff --git a/config/examples/nxp-ls1028a-tpm.config b/config/examples/nxp-ls1028a-tpm.config new file mode 100644 index 000000000..91a4752e7 --- /dev/null +++ b/config/examples/nxp-ls1028a-tpm.config @@ -0,0 +1,65 @@ +ARCH=AARCH64 +TARGET=nxp_ls1028a +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +DEBUG_UART?=1 +VTOR?=0 +CORTEX_M0?=0 +NO_ASM?=0 +EXT_FLASH?=1 +SPI_FLASH?=0 +## Force app to be copied into ram +NO_XIP?=1 +UART_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=0 +WOLFBOOT_VERSION?=0 +V?=0 +NO_MPU?=0 +SPMATH?=1 +RAM_CODE?=0 +DUALBANK_SWAP?=0 +PKA?=0 + +WOLFTPM=1 + +MEASURED_BOOT?=0 +MEASURED_PCR_A?=3 + +WOLFBOOT_TPM_KEYSTORE?=1 +WOLFBOOT_TPM_KEYSTORE_NV_INDEX?=25166336 +WOLFBOOT_TPM_POLICY_NV_INDEX?=25166337 +WOLFBOOT_TPM_PCR_INDEX?=16 + +# NOR Base Address +ARCH_FLASH_OFFSET?=0x20000000 + +# Flash Sector Size (128 KB) +WOLFBOOT_SECTOR_SIZE=0x20000 + +# wolfBoot start address +WOLFBOOT_ORIGIN=0x20020000 + +# wolfBoot partition size +BOOTLOADER_PARTITION_SIZE=0x20000 + +# Application Partition size +WOLFBOOT_PARTITION_SIZE?=0x20000 + +# Location in Flash for Application Partition +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20040000 + +# Load Partition to RAM Address +WOLFBOOT_LOAD_ADDRESS?=0x18020100 + +# Location in Flash for Update Partition +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x20060000 + +# Location of temporary sector used during updates +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20080000 + +# DTS (Device Tree) +WOLFBOOT_LOAD_DTS_ADDRESS?=0x80000000 +WOLFBOOT_DTS_BOOT_ADDRESS?=0x20F00000 +WOLFBOOT_DTS_UPDATE_ADDRESS?=0x20F00000 diff --git a/config/examples/nxp-ls1028a.config b/config/examples/nxp-ls1028a.config new file mode 100644 index 000000000..366b7dcee --- /dev/null +++ b/config/examples/nxp-ls1028a.config @@ -0,0 +1,55 @@ +ARCH=AARCH64 +TARGET=nxp_ls1028a +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +DEBUG_UART?=1 +VTOR?=0 +CORTEX_M0?=0 +NO_ASM?=0 +EXT_FLASH?=1 +SPI_FLASH?=0 +## Force app to be copied into ram +NO_XIP?=1 +UART_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=0 +WOLFBOOT_VERSION?=0 +V?=0 +NO_MPU?=0 +SPMATH?=1 +RAM_CODE?=0 +DUALBANK_SWAP?=0 +PKA?=0 + +# NOR Base Address +ARCH_FLASH_OFFSET?=0x20000000 + +# Flash Sector Size (128 KB) +WOLFBOOT_SECTOR_SIZE=0x20000 + +# wolfBoot start address +WOLFBOOT_ORIGIN=0x20020000 + +# wolfBoot partition size +BOOTLOADER_PARTITION_SIZE=0x20000 + +# Application Partition size +WOLFBOOT_PARTITION_SIZE?=0x20000 + +# Location in Flash for Application Partition +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20040000 + +# Load Partition to RAM Address +WOLFBOOT_LOAD_ADDRESS?=0x18020100 + +# Location in Flash for Update Partition +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x20060000 + +# Location of temporary sector used during updates +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20080000 + +# DTS (Device Tree) +WOLFBOOT_LOAD_DTS_ADDRESS?=0x80000000 +WOLFBOOT_DTS_BOOT_ADDRESS?=0x20F00000 +WOLFBOOT_DTS_UPDATE_ADDRESS?=0x20F00000 diff --git a/config/examples/raspi3.config b/config/examples/raspi3.config index 5b7bfdf39..13ef84d8a 100644 --- a/config/examples/raspi3.config +++ b/config/examples/raspi3.config @@ -4,6 +4,7 @@ SIGN?=RSA4096 HASH?=SHA3 DEBUG?=1 VTOR?=1 +NO_XIP?=1 SPMATH?=1 IMAGE_HEADER_SIZE?=1024 PKA?=1 diff --git a/docs/Targets.md b/docs/Targets.md index de433d72d..3c0fd508b 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -16,6 +16,7 @@ This README describes configuration of supported targets. * [NXP iMX-RT](#nxp-imx-rt) * [NXP Kinetis](#nxp-kinetis) * [NXP LPC54xxx](#nxp-lpc54xxx) +* [NXP LS1028A](#nxp-ls1028a) * [NXP MCXA153](#nxp-mcxa153) * [NXP P1021 PPC](#nxp-qoriq-p1021-ppc) * [NXP T1024 PPC](#nxp-qoriq-t1024-ppc) @@ -1073,6 +1074,97 @@ arm-none-eabi-gdb wolfboot.elf -ex "target remote localhost:3333" ``` +## NXP LS1028A + +The LS1028A is a AARCH64 armv8-a Cortex-A72 processor. Support has been tested with the NXP LS1028ARDB. + +Example configurations for this target are provided in: +* NXP LS1028A: [/config/examples/nxp-ls1028a.config](/config/examples/nxp-ls1028a.config). +* NXP LS1028A with TPM: [/config/examples/nxp-ls1028a-tpm.config](/config/examples/nxp-ls1028a-tpm.config). + +### Building wolfBoot for NXP LS1028A + +1. Download `aarch64-none-elf-` toolchain. + +2. Copy the example `nxp-ls1028a.cofig` file to root directory and rename to `.config` + +3. Build keytools and wolfboot + +``` +cp ./config/examples/nxp-ls1028a.config .config +make distclean +make keytools +make +``` + +This should output 3 binary files, `wolfboot.bin`, `image_v1_signed.bin` and `factory.bin` +- `wolfboot.bin` is the wolfboot binary +- `image_v1_signed.bin` is the signed application image and by default is `test-app/app_nxp_ls1028a` +- `factory.bin` is the two binaries merged together + + +### Hardware Setup LS1028ARDB + +DIP Switch Configuraiton for XSPI_NOR_BOOT: +``` +SW2 : 0xF8 = 11111000 SW3 : 0x70 = 01110000 SW5 : 0x20 = 00100000 +Where '1' = UP/ON +``` + +UART Configuraiton: +``` +Baud Rate: 115200 +Data Bits: 8 +Parity: None +Stop Bits: 1 +Flow Control: None +Specify device type - PC16552D +Configured for UART1 DB9 Connector +``` + +### Programming NXP LS1028A + +Programming requires three components: +1. RCW binary - Distribured by NXP at `https://github.com/nxp-qoriq/qoriq-rcw-bin` or can be generated using `https://github.com/nxp-qoriq/rcw/tree/master/ls1028ardb/R_SQPP_0x85bb` (tested with `rcw_1300.bin`) +2. woflBoot +3. Application - Test app found in `test-app/app_nxp_ls1028a.c` + +Once you have all components, you can use a lauterbach or CW to flash NOR flash. You must flash RCW, wolfboot and singed_image. `factory.bin` can be used which is wolfboot and the signed image merged. You will need to build a signed image for every update to the application code, which can be done by using keytools in `tools/keytools/sign` see `docs/Signing.md` for more details +and to sign a custom image. + +``` +Usage: tools/keytools/sign [options] image key version +``` + +#### Lauterbach Flashing and Debugging + +1. Launch lauterbach and open the demo script `debug_wolfboot.cmm`. +2. Open any desired debug windows. +3. Hit the play button on the demo script. +4. It should pop up with a code window and at the reset startpoint. (May requrie a reset or power cycle) + +``` +./t32/bin/macosx64/t32marm-qt + +Open Script > debug_wolfboot.cmm +``` + +You can modify the Lauterbach NOR flash demo or use `debug_wolfboot.cmm` script, just make sure the flash offset for +the RCW is `0x0` and the address offset for wolboot is `0x1000`. + +#### Other Tools + +1. Make sure the memory addresses are alinged with the `.config` file. +2. Note the important NOR flash addresses in the defualt config are as follows. +3. RCW location is offset `0x0` or `0x20000000` memory mapped. +4. Wolfboot location is offset `0x1000` or `0x20001000` where wolfboot starts. +5. Application location is offset `0x20000` or `0x20020000` where application code goes. +6. Update location is offset `0x40000` or `0x20040000` where the new or updated applciaiton goes. +7. Load Location is `0x18020100` which is OCRAM or where the applciaiton code is loaded if using RAM loading from +8. DTS Location is +9. Update memory locations as neeeded. + + ## Cortex-A53 / Raspberry PI 3 (experimental) Tested using `https://github.com/raspberrypi/linux` on Ubuntu 20 diff --git a/docs/measured_boot.md b/docs/measured_boot.md index c95b91efc..f02d42a60 100644 --- a/docs/measured_boot.md +++ b/docs/measured_boot.md @@ -39,7 +39,7 @@ To enable measured boot add `MEASURED_BOOT=1` setting in your wolfBoot config. It is also necessary to select the PCR (index) where the measurement will be stored. -Selection is made using the `MEASURED_BOOT_PCR_A=[index]` setting. Add this +Selection is made using the `MEASURED_PCR_A=[index]` setting. Add this setting in your wolfBoot config and replace `[index]` with a number between 0 and 23. Below you will find guidelines for selecting a PCR index. diff --git a/hal/nxp_ls1028a-ocram.ld b/hal/nxp_ls1028a-ocram.ld new file mode 100644 index 000000000..8ea5dc193 --- /dev/null +++ b/hal/nxp_ls1028a-ocram.ld @@ -0,0 +1,111 @@ +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_vector_table) + +MEMORY +{ + /*The flash address range on LS1028A RDB is 0x20000000 - 0x23FFFFFF.*/ + FLASH (rx) : ORIGIN = @WOLFBOOT_ORIGIN@, LENGTH = @BOOTLOADER_PARTITION_SIZE@ + + /* DDR4 - 2GB */ + DRAM (rwx) : ORIGIN = 0x80001000 , LENGTH = 0xBFFFFFFF + + /* OCRAM 128K for startup RAM */ + OCRAM (rwx) : ORIGIN = 0x18000000, LENGTH = 128K +} + +SECTIONS +{ + PROVIDE (_DDR_ADDRESS = 0x80001000); + PROVIDE (_OCRAM_ADDRESS = 0x18000000); + PROVIDE (_FLASH_ADDRESS = @WOLFBOOT_ORIGIN@); + PROVIDE (_CORE_NUMBER = 0); + PROVIDE (_MEMORY_SIZE = LENGTH(OCRAM)); + PROVIDE (_FLASH_SIZE = LENGTH(FLASH)); + PROVIDE (_STACK_SIZE = 20K); + + .boot : + { + PROVIDE(_vector_table = .); + ._vector_table = .; + . = ALIGN(0x800); + KEEP(*(.vector_table)) + KEEP(*(.boot*)) + } > OCRAM + + + /* Read-only sections, merged into text segment: */ + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.got : { *(.rela.got) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + + .text : + { + _start_text = .; + *(.text*) + *(.note.*) + . = ALIGN(8); + _end_text = .; + } > OCRAM + + .rodata : + { + _rodata_start = .; + *(.rodata) + *(.rodata.*) + . = ALIGN(8); + _rodata_end = .; + } > OCRAM + + PROVIDE(_stored_data = .); + + .data : + { + _start_data = .; + KEEP(*(.data .data.* .gnu.linkonce.d.*)) + . = ALIGN(8); + KEEP(*(.ramcode)) + . = ALIGN(8); + _end_data = .; + } > OCRAM + + .bss : + { + _start_bss = .; + __bss_start__ = .; + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > OCRAM + + . = ALIGN(16); + .stack : + { + _start_stack = .; + . = . + _STACK_SIZE; + _end_stack = .; + } > OCRAM + + PROVIDE(_stack_base = .); +} \ No newline at end of file diff --git a/hal/nxp_ls1028a.c b/hal/nxp_ls1028a.c new file mode 100644 index 000000000..e7edcb431 --- /dev/null +++ b/hal/nxp_ls1028a.c @@ -0,0 +1,888 @@ +/* nxp_ls1028a.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include +#include +#include "image.h" +#include "printf.h" + +#ifdef TARGET_nxp_ls1028a + +#ifndef ARCH_AARCH64 +# error "wolfBoot ls1028a HAL: wrong architecture selected. Please compile with ARCH=AARCH64." +#endif + +#include "nxp_ls1028a.h" + +/* HAL options */ +#define ENABLE_DDR + +#define BAUD_RATE 115200 +#define UART_SEL 0 /* select UART 0 or 1 */ + + +void hal_flash_init(void); +void switch_el3_to_el2(void); +extern void mmu_enable(void); + +#ifdef DEBUG_UART +void uart_init(void) +{ + /* calc divisor for UART + * example config values: + * clock_div, baud, base_clk 163 115200 400000000 + * +0.5 to round up + */ + uint32_t div = (((SYS_CLK / 2.0) / (16 * BAUD_RATE)) + 0.5); + + while (!(UART_LSR(UART_SEL) & UART_LSR_TEMT)); + + /* set ier, fcr, mcr */ + UART_IER(UART_SEL) = 0; + UART_FCR(UART_SEL) = (UART_FCR_TFR | UART_FCR_RFR | UART_FCR_FEN); + + /* enable baud rate access (DLAB=1) - divisor latch access bit*/ + UART_LCR(UART_SEL) = (UART_LCR_DLAB | UART_LCR_WLS); + /* set divisor */ + UART_DLB(UART_SEL) = (div & 0xff); + UART_DMB(UART_SEL) = ((div>>8) & 0xff); + /* disable rate access (DLAB=0) */ + UART_LCR(UART_SEL) = (UART_LCR_WLS); +} + +void uart_write(const char* buf, uint32_t sz) +{ + uint32_t pos = 0; + while (sz-- > 0) { + char c = buf[pos++]; + if (c == '\n') { /* handle CRLF */ + while (!(UART_LSR(UART_SEL) & UART_LSR_THRE)); + UART_THR(UART_SEL) = '\r'; + } + while (!(UART_LSR(UART_SEL) & UART_LSR_THRE)); + UART_THR(UART_SEL) = c; + } +} +#endif /* DEBUG_UART */ + + + +/* SPI interface */ + +/* Clear and halt the SPI controller*/ +static void spi_close(unsigned int sel) +{ + /* Halt, flush and set as master */ + SPI_MCR(sel) = SPI_MCR_MASTER_HALT; +} + +/*Clear the SPI controller and setup as a running master*/ +static void spi_open(unsigned int sel) +{ + spi_close(sel); + /* Setup CTAR0 */ + SPI_CTAR0(sel) = SPI_CTAR_8_00MODE_8DIV; + /* Enable as master */ + SPI_MCR(sel) = SPI_MCR_MASTER_RUNNING; +} + +static int spi_can_rx(unsigned int sel) +{ + return !!(SPI_SR(sel) & SPI_SR_RXCTR); +} + +static unsigned char spi_pop_rx(unsigned int sel) +{ + return SPI_POPR(sel) & 0xFF; +} + +static void spi_flush_rx(unsigned int sel) +{ + unsigned char rx_data; + while (spi_can_rx(sel)) { + rx_data = spi_pop_rx(sel); + } + (void) rx_data; +} + +static int spi_can_tx(unsigned int sel) +{ + return !!(SPI_SR(sel) & SPI_SR_TFFF); +} + +static void spi_push_tx(unsigned int sel, unsigned int pcs, unsigned char data, + int last) +{ + SPI_PUSHR(sel) = (last ? SPI_PUSHR_LAST : SPI_PUSHR_CONT) + | SPI_PUSHR_PCS(pcs) | data; +} + +/* Perform a SPI transaction. Set cont!=0 to not let CS go low after this*/ +static void spi_transaction(unsigned int sel, unsigned int pcs, + const unsigned char *out, unsigned char *in, unsigned int size, + int cont) +{ + unsigned int tx_count = size; + unsigned int rx_count = size; + int last = 0; + unsigned char rx_data = 0; + unsigned char tx_data = 0; + + /* XXX No parameter validation */ + + /* Flush RX FIFO */ + spi_flush_rx(sel); + + /* Nothing to do? */ + if (!size) + return; + + while (rx_count > 0) { + /* Try to push TX data */ + while ((tx_count > 0) && ((rx_count - tx_count) < SPI_FIFO_DEPTH) + && spi_can_tx(sel)) { + if (out) { + tx_data = *out; + out++; + } + tx_count--; + last = (!cont && !tx_count); + spi_push_tx(sel, pcs, tx_data, last); + } + + /* Try to pop RX data */ + while ((rx_count > 0) && spi_can_rx(sel)) { + rx_data = spi_pop_rx(sel); + if (in) { + *in = rx_data; + in++; + } + rx_count--; + } + } +} + +/*#define TPM_TEST*/ +#ifdef TPM_TEST +void read_tpm_id(void) +{ + /* Read 4 bytes from offset D40F00. Assumes 0 wait state on TPM */ + unsigned char out[8] = { 0x83, 0xD4, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00 }; + unsigned char in[8] = { 0 }; + unsigned char in2[8] = { 0 }; + unsigned int counter; + + /* LS1028A SPI to the MikroBus uses SPI3 (sel is 2) and CS 0 */ + #ifndef SPI_SEL_TPM + #define SPI_SEL_TPM 2 + #endif + + #ifndef SPI_CS_TPM + #define SPI_CS_TPM 0 + #endif + + spi_open(SPI_SEL_TPM); + + /* Single transaction */ + spi_transaction(SPI_SEL_TPM, SPI_CS_TPM, out, in, sizeof(out), 0); + + /* Use individual transactions with cont set */ + for (counter = 0; counter < (sizeof(out) - 1); counter++) { + spi_transaction(SPI_SEL_TPM, SPI_CS_TPM, &out[counter], &in2[counter], 1, + 1); + } + spi_transaction(SPI_SEL_TPM, SPI_CS_TPM, &out[counter], &in2[counter], 1, 0); + + spi_close(SPI_SEL_TPM); + + (void) in; + (void) in2; +} +#endif + +void nxp_ls1028a_spi_init(unsigned int sel) +{ + /* TODO: Expose more configuration options */ + spi_open(sel); +} + +int nxp_ls1028a_spi_xfer(unsigned int sel, unsigned int cs, + const unsigned char *out, unsigned char *in, + unsigned int size, int cont) +{ + /* TODO Make spi_transaction actually return errors */ + spi_transaction(sel, cs, out, in, size, cont); + return 0; +} + +void nxp_ls1028a_spi_deinit(unsigned int sel) +{ + spi_close(sel); +} + + +void hal_delay_us(uint32_t us) { + uint64_t delay = (uint64_t)SYS_CLK * us / 1000000; + volatile uint32_t i = 0; + for (i = 0; i < delay; i++) { + asm volatile("nop"); + } +} + +/* Fixed addresses */ +static const void* kernel_addr = (void*)WOLFBOOT_PARTITION_BOOT_ADDRESS; +static const void* update_addr = (void*)WOLFBOOT_PARTITION_UPDATE_ADDRESS; + +void* hal_get_primary_address(void) +{ + return (void*)kernel_addr; +} + +void* hal_get_update_address(void) +{ + return (void*)update_addr; +} + +void* hal_get_dts_address(void) +{ + return (void*)WOLFBOOT_LOAD_DTS_ADDRESS; +} + +void* hal_get_dts_update_address(void) +{ + return (void*)NULL; +} + +void erratum_err050568(void) +{ + /* Use IP bus only if systembus PLL is 300MHz (Dont use 300MHz) */ +} + +/* Application on Serial NOR Flash device 18.6.3 */ +void xspi_init(void) +{ + /* Configure module control register */ + XSPI_MCR0 = XSPI_MCR0_CFG; + XSPI_MCR1 = XSPI_MCR1_CFG; + XSPI_MCR2 = XSPI_MCR2_CFG; + + /* Clear RX/TX fifos */ + XSPI_IPRXFCR = XSPI_IPRXFCR_CFG; /* Note: RX/TX Water Mark can be set here default is 64bit */ + XSPI_IPTXFCR = XSPI_IPTXFCR_CFG; /* Increase size to reduce transfer requests */ + + /* Configure AHB bus control register (AHBCR) and AHB RX Buffer control register (AHBRXBUFxCR0) */ + XSPI_AHBCR = XSPI_AHBCR_CFG; + + XSPI_AHBRXBUFnCR0(0) = XSPI_AHBRXBUF0CR_CFG; + XSPI_AHBRXBUFnCR0(1) = XSPI_AHBRXBUF1CR_CFG; + XSPI_AHBRXBUFnCR0(2) = XSPI_AHBRXBUF2CR_CFG; + XSPI_AHBRXBUFnCR0(3) = XSPI_AHBRXBUF3CR_CFG; + XSPI_AHBRXBUFnCR0(4) = XSPI_AHBRXBUF4CR_CFG; + XSPI_AHBRXBUFnCR0(5) = XSPI_AHBRXBUF5CR_CFG; + XSPI_AHBRXBUFnCR0(6) = XSPI_AHBRXBUF6CR_CFG; + XSPI_AHBRXBUFnCR0(7) = XSPI_AHBRXBUF7CR_CFG; + + /* Configure Flash control registers (FLSHxCR0,FLSHxCR1,FLSHxCR2) */ + XSPI_FLSHA1CR0 = XSPI_FLSHA1CR0_CFG; + XSPI_FLSHA2CR0 = XSPI_FLSHA2CR0_CFG; + XSPI_FLSHB1CR0 = XSPI_FLSHB1CR0_CFG; + XSPI_FLSHB2CR0 = XSPI_FLSHB2CR0_CFG; + + XSPI_FLSHA1CR1 = XSPI_FLSHA1CR1_CFG; + XSPI_FLSHA2CR1 = XSPI_FLSHA2CR1_CFG; + XSPI_FLSHB1CR1 = XSPI_FLSHB1CR1_CFG; + XSPI_FLSHB2CR1 = XSPI_FLSHB2CR1_CFG; + XSPI_FLSHA1CR2 = XSPI_FLSHA1CR2_CFG; + XSPI_FLSHA2CR2 = XSPI_FLSHA2CR2_CFG; + XSPI_FLSHB1CR2 = XSPI_FLSHB1CR2_CFG; + XSPI_FLSHB2CR2 = XSPI_FLSHB2CR2_CFG; + + /* Configure DLL control register (DLLxCR) according to sample clock source selection */ + XSPI_DLLACR = XSPI_DLLACR_CFG; + XSPI_DLLBCR = XSPI_DLLBCR_CFG; +} + +void xspi_lut_lock(void) +{ + XSPI_LUTKEY = LUT_KEY; + XSPI_LUT_LOCK() +} + +void xspi_lut_unlock(void) +{ + XSPI_LUTKEY = LUT_KEY; + XSPI_LUT_UNLOCK() +} + +void hal_flash_init(void) +{ + xspi_lut_unlock(); + + xspi_init(); + + /* Fast Read */ + XSPI_LUT(LUT_INDEX_READ) = XSPI_LUT_SEQ(RADDR_SDR, LUT_PAD_SINGLE, LUT_OP_ADDR3B, CMD_SDR, LUT_PAD_SINGLE, LUT_OP_READ3B); + XSPI_LUT(1) = XSPI_LUT_SEQ(STOP, LUT_PAD_SINGLE, 0x0, READ_SDR, LUT_PAD_SINGLE, 0x04); + XSPI_LUT(2) = 0x0; + XSPI_LUT(3) = 0x0; + + /* Write Enable */ + XSPI_LUT(LUT_INDEX_WRITE_EN) = XSPI_LUT_SEQ(STOP, LUT_PAD_SINGLE, 0x0, CMD_SDR, LUT_PAD_SINGLE, LUT_OP_WE); + XSPI_LUT(5) = 0x0; + XSPI_LUT(6) = 0x0; + XSPI_LUT(7) = 0x0; + + /* Erase */ + XSPI_LUT(LUT_INDEX_SE) = XSPI_LUT_SEQ(RADDR_SDR, LUT_PAD_SINGLE, LUT_OP_ADDR3B, CMD_SDR, LUT_PAD_SINGLE, LUT_OP_SE); + XSPI_LUT(9) = 0x0; + XSPI_LUT(10) = 0x0; + XSPI_LUT(11) = 0x0; + + /* Subsector 4k Erase */ + XSPI_LUT(LUT_INDEX_SSE4K) = XSPI_LUT_SEQ(RADDR_SDR, LUT_PAD_SINGLE, LUT_OP_ADDR3B, CMD_SDR, LUT_PAD_SINGLE, LUT_OP_SE_4K); + XSPI_LUT(13) = 0x0; + XSPI_LUT(14) = 0x0; + XSPI_LUT(15) = 0x0; + + /* Page Program */ + XSPI_LUT(LUT_INDEX_PP) = XSPI_LUT_SEQ(RADDR_SDR, LUT_PAD_SINGLE, LUT_OP_ADDR3B, CMD_SDR, LUT_PAD(1), LUT_OP_PP); + XSPI_LUT(17) = XSPI_LUT_SEQ(STOP, LUT_PAD_SINGLE, 0x0, WRITE_SDR, LUT_PAD_SINGLE, 0x1); + XSPI_LUT(18) = 0x0; + XSPI_LUT(19) = 0x0; + + /* Read Flag Status Regsiter */ + XSPI_LUT(LUT_INDEX_RDSR) = XSPI_LUT_SEQ(READ_SDR, LUT_PAD_SINGLE, LUT_OP_1BYTE, CMD_SDR, LUT_PAD_SINGLE, LUT_OP_RDSR); + XSPI_LUT(21) = 0x0; + XSPI_LUT(22) = 0x0; + XSPI_LUT(23) = 0x0; + + xspi_lut_lock(); +} + +/* Called from boot_aarch64_start.S */ +void hal_ddr_init(void) +{ +#ifdef ENABLE_DDR + uint64_t counter = 0; + DDR_DDRCDR_1 = DDR_DDRCDR_1_VAL; + DDR_SDRAM_CLK_CNTL = DDR_SDRAM_CLK_CNTL_VAL; + + /* Setup DDR CS (chip select) bounds */ + DDR_CS_BNDS(0) = DDR_CS0_BNDS_VAL; + DDR_CS_BNDS(1) = DDR_CS1_BNDS_VAL; + DDR_CS_BNDS(2) = DDR_CS2_BNDS_VAL; + DDR_CS_BNDS(3) = DDR_CS3_BNDS_VAL; + + /* DDR SDRAM timing configuration */ + DDR_TIMING_CFG_0 = DDR_TIMING_CFG_0_VAL; + DDR_TIMING_CFG_1 = DDR_TIMING_CFG_1_VAL; + DDR_TIMING_CFG_2 = DDR_TIMING_CFG_2_VAL; + DDR_TIMING_CFG_3 = DDR_TIMING_CFG_3_VAL; + DDR_TIMING_CFG_4 = DDR_TIMING_CFG_4_VAL; + DDR_TIMING_CFG_5 = DDR_TIMING_CFG_5_VAL; + DDR_TIMING_CFG_6 = DDR_TIMING_CFG_6_VAL; + DDR_TIMING_CFG_7 = DDR_TIMING_CFG_7_VAL; + DDR_TIMING_CFG_8 = DDR_TIMING_CFG_8_VAL; + + DDR_ZQ_CNTL = DDR_ZQ_CNTL_VAL; + DDR_DQ_MAP_0 = DDR_DQ_MAP_0_VAL; + DDR_DQ_MAP_1 = DDR_DQ_MAP_1_VAL; + DDR_DQ_MAP_2 = DDR_DQ_MAP_2_VAL; + DDR_DQ_MAP_3 = DDR_DQ_MAP_3_VAL; + + /* DDR SDRAM mode configuration */ + DDR_SDRAM_CFG_3 = DDR_SDRAM_CFG_3_VAL; + + DDR_SDRAM_MODE = DDR_SDRAM_MODE_VAL; + DDR_SDRAM_MODE_2 = DDR_SDRAM_MODE_2_VAL; + DDR_SDRAM_MODE_3 = DDR_SDRAM_MODE_3_VAL; + DDR_SDRAM_MODE_4 = DDR_SDRAM_MODE_4_VAL; + DDR_SDRAM_MODE_5 = DDR_SDRAM_MODE_5_VAL; + DDR_SDRAM_MODE_6 = DDR_SDRAM_MODE_6_VAL; + DDR_SDRAM_MODE_7 = DDR_SDRAM_MODE_7_VAL; + DDR_SDRAM_MODE_8 = DDR_SDRAM_MODE_8_VAL; + DDR_SDRAM_MODE_9 = DDR_SDRAM_MODE_9_VAL; + DDR_SDRAM_MODE_10 = DDR_SDRAM_MODE_10_VAL; + DDR_SDRAM_MODE_11 = DDR_SDRAM_MODE_11_VAL; + DDR_SDRAM_MODE_12 = DDR_SDRAM_MODE_12_VAL; + DDR_SDRAM_MODE_13 = DDR_SDRAM_MODE_13_VAL; + DDR_SDRAM_MODE_14 = DDR_SDRAM_MODE_14_VAL; + DDR_SDRAM_MODE_15 = DDR_SDRAM_MODE_15_VAL; + DDR_SDRAM_MODE_16 = DDR_SDRAM_MODE_16_VAL; + DDR_SDRAM_MD_CNTL = DDR_SDRAM_MD_CNTL_VAL; + + /* DDR Configuration */ + DDR_SDRAM_INTERVAL = DDR_SDRAM_INTERVAL_VAL; + DDR_DATA_INIT = DDR_DATA_INIT_VAL; + + DDR_WRLVL_CNTL = DDR_WRLVL_CNTL_VAL; + DDR_WRLVL_CNTL_2 = DDR_WRLVL_CNTL_2_VAL; + DDR_WRLVL_CNTL_3 = DDR_WRLVL_CNTL_3_VAL; + + DDR_SR_CNTR = 0; + DDR_SDRAM_RCW_1 = DDR_SDRAM_RCW_1_VAL; + DDR_SDRAM_RCW_2 = DDR_SDRAM_RCW_2_VAL; + DDR_SDRAM_RCW_3 = DDR_SDRAM_RCW_3_VAL; + DDR_SDRAM_RCW_4 = DDR_SDRAM_RCW_4_VAL; + DDR_SDRAM_RCW_5 = DDR_SDRAM_RCW_5_VAL; + DDR_SDRAM_RCW_6 = DDR_SDRAM_RCW_6_VAL; + DDR_DDRCDR_2 = DDR_DDRCDR_2_VAL; + DDR_SDRAM_CFG_2 = DDR_SDRAM_CFG_2_VAL; + DDR_INIT_ADDR = 0; + DDR_INIT_EXT_ADDR = 0; + DDR_ERR_DISABLE = 0; + DDR_ERR_INT_EN = DDR_ERR_INT_EN_VAL; + + DDR_DDRDSR_1 = DDR_DDRDSR_1_VAL; + DDR_DDRDSR_2 = DDR_DDRDSR_2_VAL; + DDR_ERR_SBE = DDR_ERR_SBE_VAL; + + DDR_CS_CONFIG(0) = DDR_CS0_CONFIG_VAL; + DDR_CS_CONFIG(1) = DDR_CS1_CONFIG_VAL; + DDR_CS_CONFIG(2) = DDR_CS2_CONFIG_VAL; + DDR_CS_CONFIG(3) = DDR_CS3_CONFIG_VAL; + + /* Set values, but do not enable the DDR yet */ + DDR_SDRAM_CFG = (DDR_SDRAM_CFG_VAL & ~DDR_SDRAM_CFG_MEM_EN); + + hal_delay_us(500); + asm volatile("isb"); + + /* Enable controller */ + DDR_SDRAM_CFG &= ~(DDR_SDRAM_CFG_BI); + DDR_SDRAM_CFG |= DDR_SDRAM_CFG_MEM_EN; + asm volatile("isb"); + + /* Wait for data initialization is complete */ + while ((DDR_SDRAM_CFG_2 & DDR_SDRAM_CFG2_D_INIT)) { + counter++; + } + + (void)counter; + +#endif +} + +void xspi_writereg(uint32_t* addr, uint32_t val) +{ + *(volatile uint32_t *)(addr) = val; +} + +void xspi_write_en(uint32_t addr) +{ + XSPI_IPTXFCR = XSPI_IPRCFCR_FLUSH; + XSPI_IPCR0 = addr; + XSPI_IPCR1 = XSPI_ISEQID(LUT_INDEX_WRITE_EN) | 1; + XSPI_IPCMD_START(); + + while(!(XSPI_INTR & XSPI_IPCMDDONE)); + + XSPI_INTR |= XSPI_IPCMDDONE; +} + +void xspi_read_sr(uint8_t* rxbuf, uint32_t addr, uint32_t len) +{ + uint32_t data = 0; + + /* Read IP CR regsiter */ + uint32_t rxfcr = XSPI_IPRXFCR; + + /* Flush RX fifo */ + rxfcr = rxfcr | XSPI_IPRCFCR_FLUSH; + XSPI_IPTXFCR = rxfcr; + + /* Trigger read SR command */ + XSPI_IPCR0 = addr; + XSPI_IPCR1 = XSPI_ISEQID(LUT_INDEX_RDSR) | len; + XSPI_IPCMD_START(); + + while(!(XSPI_INTR & XSPI_IPCMDDONE)); + + XSPI_INTR |= XSPI_IPCMDDONE; + + data = XSPI_RFD(0); + memcpy(rxbuf, &data, len); + + XSPI_IPRXFCR = XSPI_IPRCFCR_FLUSH; + XSPI_INTR = XSPI_IPRXWA; + XSPI_INTR = XSPI_IPCMDDONE; +} + +void xspi_sw_reset(void) +{ + XSPI_SWRESET(); + while (XSPI_MCR0 & XSPI_SW_RESET); +} + +void xspi_flash_write(uintptr_t address, const uint8_t *data, uint32_t len) +{ + uint32_t size = 0; + uint32_t tx_data = 0; + uint32_t size_wm = 0; + uint32_t loop_cnt = 0; + uint32_t remaining, rem_size = 0; + uint32_t i = 0, j = 0; + + while (len) { + size = len > XSPI_IP_BUF_SIZE ? XSPI_IP_BUF_SIZE : len; + + XSPI_IPCR0 = address; + loop_cnt = size / XSPI_IP_WM_SIZE; + + /* Fill TX fifos */ + for (i = 0; i < loop_cnt; i++) { + /* Wait for TX fifo ready */ + while (!(XSPI_INTR & XSPI_INTR_IPTXWE_MASK)); + + for(j = 0; j < XSPI_IP_WM_SIZE; j+=4) { + memcpy(&tx_data, data++, 4); + xspi_writereg((uint32_t*)XSPI_TFD_BASE + j, tx_data); + } + + /* Reset fifo */ + XSPI_INTR = XSPI_INTR_IPTXWE_MASK; + } + + remaining = size % XSPI_IP_WM_SIZE; + + /* Write remaining data for non aligned data */ + if (remaining) { + /* Wait for fifo Empty */ + while(!(XSPI_INTR & XSPI_INTR_IPTXWE_MASK)); + + for(j = 0; j < remaining; j+=4) { + tx_data = 0; + rem_size = (remaining < 4) ? remaining : 4; + memcpy(&tx_data, data++, rem_size); + xspi_writereg((uint32_t*)XSPI_TFD_BASE + j, tx_data); + } + + /* Reset fifo */ + XSPI_INTR = XSPI_INTR_IPTXWE_MASK; + } + + XSPI_IPCR1 = XSPI_ISEQID(LUT_INDEX_PP) | size; + XSPI_IPCMD_START(); + + /* Wait command done */ + while (!(XSPI_INTR & XSPI_IPCMDDONE)) + + /* Flush fifo, set done flag */ + XSPI_IPTXFCR = XSPI_IPRCFCR_FLUSH; + XSPI_INTR = XSPI_IPCMDDONE; + + len -= size; + address += size; + } +} + +void xspi_flash_sec_erase(uintptr_t address) +{ + XSPI_IPCR0 = address; + XSPI_IPCR1 = XSPI_ISEQID(LUT_INDEX_SE) | FLASH_ERASE_SIZE; + XSPI_IPCMD_START(); + + while(!(XSPI_INTR & XSPI_IPCMDDONE)); + + XSPI_INTR &= ~XSPI_IPCMDDONE; +} + + +void hal_flash_unlock(void) +{ +} +void hal_flash_lock(void) +{ +} + +int hal_flash_write(uintptr_t address, const uint8_t *data, int len) +{ + xspi_write_en(address); + xspi_flash_write(address, data, len); + + return len; +} + +int hal_flash_erase(uintptr_t address, int len) +{ + uint32_t num_sectors = 0; + uint32_t i = 0; + uint8_t status[4] = {0, 0, 0, 0}; + + num_sectors = len / FLASH_ERASE_SIZE; + num_sectors += (len % FLASH_ERASE_SIZE) ? 1 : 0; + + for (i = 0; i < num_sectors; i++) { + xspi_write_en(address + i * FLASH_ERASE_SIZE); + xspi_flash_sec_erase(address + i * FLASH_ERASE_SIZE); + + while (!(status[0] & FLASH_READY_MSK)) { + xspi_read_sr(status, 0, 1); + } + } + + xspi_sw_reset(); + + return len; +} + +#ifdef EXT_FLASH +void ext_flash_lock(void) +{ +} + +void ext_flash_unlock(void) +{ +} +int ext_flash_write(uintptr_t address, const uint8_t *data, int len) +{ + xspi_write_en(address); + xspi_flash_write(address, data, len); + + return len; +} + +int ext_flash_read(uintptr_t address, uint8_t *data, int len) +{ + address = (address & MASK_32BIT); + memcpy(data, (void*)address, len); + return len; +} + +int ext_flash_erase(uintptr_t address, int len) +{ + uint32_t num_sectors = 0; + uint32_t i = 0; + uint8_t status[4] = {0, 0, 0, 0}; + + num_sectors = len / FLASH_ERASE_SIZE; + num_sectors += (len % FLASH_ERASE_SIZE) ? 1 : 0; + + for (i = 0; i < num_sectors; i++) { + xspi_write_en(address + i * FLASH_ERASE_SIZE); + xspi_flash_sec_erase(address + i * FLASH_ERASE_SIZE); + + while (!(status[0] & FLASH_READY_MSK)) { + xspi_read_sr(status, 0, 1); + } + } + + xspi_sw_reset(); + + return len; +} +#endif /* EXT_FLASH */ + + +void hal_prepare_boot(void) +{ + #if 0 + /* TODO: EL2 */ + switch_el3_to_el2(); + #endif +} + +#ifdef TEST_HW_DDR +static int test_hw_ddr(void) +{ + int status = 0; + uint64_t counter = 0; + + DDR_MTPn(0) = 0xffffffff; + DDR_MTPn(1) = 0x00000001; + DDR_MTPn(2) = 0x00000002; + DDR_MTPn(3) = 0x00000003; + DDR_MTPn(4) = 0x00000004; + DDR_MTPn(5) = 0x00000005; + DDR_MTPn(6) = 0xcccccccc; + DDR_MTPn(7) = 0xbbbbbbbb; + DDR_MTPn(8) = 0xaaaaaaaa; + DDR_MTPn(9) = 0xffffffff; + + DDR_MTCR = DDR_MEM_TEST_EN; + + while (DDR_MTCR & DDR_MEM_TEST_EN) + counter++; + + if (DDR_ERR_SBE & 0xffff || DDR_ERR_DETECT) { + status = -1; + wolfBoot_printf("DDR ECC error\n"); + } + if (DDR_MTCR & DDR_MEM_TEST_FAIL) { + status = -1; + wolfBoot_printf("DDR self-test failed\n"); + } else { + status = 0; + wolfBoot_printf("DDR self-test passed\n"); + } + + return status; +} +#endif /* TEST_HW_DDR */ + +#ifdef TEST_DDR +static int test_ddr(void) +{ + int ret = 0; + int i; + uint32_t *ptr = (uint32_t*)(DDR_ADDRESS + TEST_DDR_OFFSET); + uint32_t tmp[TEST_DDR_SIZE/4]; + + memset(tmp, 0, sizeof(tmp)); + + /* test write to DDR */ + for (i = 0; i < TEST_DDR_SIZE/4; i++) { + ptr[i] = (uint32_t)i; + } + + /* test read from DDR */ + for (i = 0; i < TEST_DDR_SIZE/4; i++) { + tmp[i] = ptr[i]; + } + + /* compare results */ + for (i = 0; i < TEST_DDR_SIZE/4; i++) { + if (tmp[i] != (uint32_t)i) { + ret = -1; + break; + } + } + + return ret; +} +#endif /* TEST_DDR */ + +#ifdef TEST_EXT_FLASH +#define TEST_ADDRESS 0x20012000 + +static int test_flash(void) +{ + int ret; + uint32_t i; + uint8_t pageData[FLASH_PAGE_SIZE]; + + /* Erase sector */ + ret = ext_flash_erase(TEST_ADDRESS, WOLFBOOT_SECTOR_SIZE); + wolfBoot_printf("Erase Sector: Ret %d\n", ret); + + /* Write Pages */ + for (i=0; i DDR4: static, 1GB, 1600 MHz (1.6 GT/s) */ +#define DDR_ADDRESS 0x80000000 +#define DDR_FREQ 1600 +#define DDR_SIZE (2 * 1024 * 1024 * 1024) +#define DDR_N_RANKS 1 +#define DDR_RANK_DENS 0x100000000 +#define DDR_SDRAM_WIDTH 32 +#define DDR_EC_SDRAM_W 0 +#define DDR_N_ROW_ADDR 15 +#define DDR_N_COL_ADDR 10 +#define DDR_N_BANKS 2 +#define DDR_EDC_CONFIG 2 +#define DDR_BURSTL_MASK 0x0c +#define DDR_TCKMIN_X_PS 750 +#define DDR_TCMMAX_PS 1900 +#define DDR_CASLAT_X 0x0001FFE00 +#define DDR_TAA_PS 13500 +#define DDR_TRCD_PS 13500 +#define DDR_TRP_PS 13500 +#define DDR_TRAS_PS 32000 +#define DDR_TRC_PS 45500 +#define DDR_TWR_PS 15000 +#define DDR_TRFC1_PS 350000 +#define DDR_TRFC2_PS 260000 +#define DDR_TRFC4_PS 160000 +#define DDR_TFAW_PS 21000 +#define DDR_TRFC_PS 260000 +#define DDR_TRRDS_PS 3000 +#define DDR_TRRDL_PS 4900 +#define DDR_TCCDL_PS 5000 +#define DDR_REF_RATE_PS 7800000 + +#define DDR_CS0_BNDS_VAL 0x000000FF +#define DDR_CS1_BNDS_VAL 0x00000000 +#define DDR_CS2_BNDS_VAL 0x00000000 +#define DDR_CS3_BNDS_VAL 0x00000000 +#define DDR_CS0_CONFIG_VAL 0x80040422 +#define DDR_CS1_CONFIG_VAL 0x00000000 +#define DDR_CS2_CONFIG_VAL 0x00000000 +#define DDR_CS3_CONFIG_VAL 0x00000000 +#define DDR_TIMING_CFG_3_VAL 0x01111000 +#define DDR_TIMING_CFG_0_VAL 0x91550018 +#define DDR_TIMING_CFG_1_VAL 0xBAB40C42 +#define DDR_TIMING_CFG_2_VAL 0x0048C111 +#define DDR_SDRAM_CFG_VAL 0xE50C0004 +#define DDR_SDRAM_CFG_2_VAL 0x00401110 +#define DDR_SDRAM_MODE_VAL 0x03010210 +#define DDR_SDRAM_MODE_2_VAL 0x00000000 +#define DDR_SDRAM_MD_CNTL_VAL 0x0600041F +#define DDR_SDRAM_INTERVAL_VAL 0x18600618 +#define DDR_DATA_INIT_VAL 0xDEADBEEF +#define DDR_SDRAM_CLK_CNTL_VAL 0x02000000 +#define DDR_INIT_ADDR_VAL 0x00000000 +#define DDR_INIT_EXT_ADDR_VAL 0x00000000 +#define DDR_TIMING_CFG_4_VAL 0x00000002 +#define DDR_TIMING_CFG_5_VAL 0x03401400 +#define DDR_TIMING_CFG_6_VAL 0x00000000 +#define DDR_TIMING_CFG_7_VAL 0x23300000 +#define DDR_ZQ_CNTL_VAL 0x8A090705 +#define DDR_WRLVL_CNTL_VAL 0x8675F605 +#define DDR_SR_CNTL_VAL 0x00000000 +#define DDR_SDRAM_RCW_1_VAL 0x00000000 +#define DDR_SDRAM_RCW_2_VAL 0x00000000 +#define DDR_WRLVL_CNTL_2_VAL 0x06070700 +#define DDR_WRLVL_CNTL_3_VAL 0x00000008 +#define DDR_SDRAM_RCW_3_VAL 0x00000000 +#define DDR_SDRAM_RCW_4_VAL 0x00000000 +#define DDR_SDRAM_RCW_5_VAL 0x00000000 +#define DDR_SDRAM_RCW_6_VAL 0x00000000 +#define DDR_SDRAM_MODE_3_VAL 0x00010210 +#define DDR_SDRAM_MODE_4_VAL 0x00000000 +#define DDR_SDRAM_MODE_5_VAL 0x00010210 +#define DDR_SDRAM_MODE_6_VAL 0x00000000 +#define DDR_SDRAM_MODE_7_VAL 0x00010210 +#define DDR_SDRAM_MODE_8_VAL 0x00000000 +#define DDR_SDRAM_MODE_9_VAL 0x00000500 +#define DDR_SDRAM_MODE_10_VAL 0x04000000 +#define DDR_SDRAM_MODE_11_VAL 0x00000400 +#define DDR_SDRAM_MODE_12_VAL 0x04000000 +#define DDR_SDRAM_MODE_13_VAL 0x00000400 +#define DDR_SDRAM_MODE_14_VAL 0x04000000 +#define DDR_SDRAM_MODE_15_VAL 0x00000400 +#define DDR_SDRAM_MODE_16_VAL 0x04000000 +#define DDR_TIMING_CFG_8_VAL 0x02114600 +#define DDR_SDRAM_CFG_3_VAL 0x00000000 +#define DDR_DQ_MAP_0_VAL 0x5b65b658 +#define DDR_DQ_MAP_1_VAL 0xd96d8000 +#define DDR_DQ_MAP_2_VAL 0x00000000 +#define DDR_DQ_MAP_3_VAL 0x01600000 +#define DDR_DDRDSR_1_VAL 0x00000000 +#define DDR_DDRDSR_2_VAL 0x00000000 +#define DDR_DDRCDR_1_VAL 0x80040000 +#define DDR_DDRCDR_2_VAL 0x0000A181 +#define DDR_ERR_INT_EN_VAL 0x00000000 +#define DDR_ERR_SBE_VAL 0x00000000 + + +/* 12.4 DDR Memory Map */ +#define DDR_BASE (0x1080000) +#define DDR_PHY_BASE (0x1400000) + +#define DDR_CS_BNDS(n) *((volatile uint32_t*)(DDR_BASE + 0x000 + (n * 8))) /* Chip select n memory bounds */ +#define DDR_CS_CONFIG(n) *((volatile uint32_t*)(DDR_BASE + 0x080 + (n * 4))) /* Chip select n configuration */ +#define DDR_TIMING_CFG_3 *((volatile uint32_t*)(DDR_BASE + 0x100)) /* DDR SDRAM timing configuration 3 */ +#define DDR_TIMING_CFG_0 *((volatile uint32_t*)(DDR_BASE + 0x104)) /* DDR SDRAM timing configuration 0 */ +#define DDR_TIMING_CFG_1 *((volatile uint32_t*)(DDR_BASE + 0x108)) /* DDR SDRAM timing configuration 1 */ +#define DDR_TIMING_CFG_2 *((volatile uint32_t*)(DDR_BASE + 0x10C)) /* DDR SDRAM timing configuration 2 */ +#define DDR_SDRAM_CFG *((volatile uint32_t*)(DDR_BASE + 0x110)) /* DDR SDRAM control configuration */ +#define DDR_SDRAM_CFG_2 *((volatile uint32_t*)(DDR_BASE + 0x114)) /* DDR SDRAM control configuration 2 */ +#define DDR_SDRAM_MODE *((volatile uint32_t*)(DDR_BASE + 0x118)) /* DDR SDRAM mode configuration */ +#define DDR_SDRAM_MODE_2 *((volatile uint32_t*)(DDR_BASE + 0x11C)) /* DDR SDRAM mode configuration 2 */ +#define DDR_SDRAM_MD_CNTL *((volatile uint32_t*)(DDR_BASE + 0x120)) /* DDR SDRAM mode control */ +#define DDR_SDRAM_INTERVAL *((volatile uint32_t*)(DDR_BASE + 0x124)) /* DDR SDRAM interval configuration */ +#define DDR_DATA_INIT *((volatile uint32_t*)(DDR_BASE + 0x128)) /* DDR training initialization value */ +#define DDR_SDRAM_CLK_CNTL *((volatile uint32_t*)(DDR_BASE + 0x130)) /* DDR SDRAM clock control */ +#define DDR_INIT_ADDR *((volatile uint32_t*)(DDR_BASE + 0x148)) /* DDR training initialization address */ +#define DDR_INIT_EXT_ADDR *((volatile uint32_t*)(DDR_BASE + 0x14C)) /* DDR training initialization extended address */ +#define DDR_TIMING_CFG_4 *((volatile uint32_t*)(DDR_BASE + 0x160)) /* DDR SDRAM timing configuration 4 */ +#define DDR_TIMING_CFG_5 *((volatile uint32_t*)(DDR_BASE + 0x164)) /* DDR SDRAM timing configuration 5 */ +#define DDR_TIMING_CFG_6 *((volatile uint32_t*)(DDR_BASE + 0x168)) /* DDR SDRAM timing configuration 6 */ +#define DDR_TIMING_CFG_7 *((volatile uint32_t*)(DDR_BASE + 0x16C)) /* DDR SDRAM timing configuration 7 */ +#define DDR_ZQ_CNTL *((volatile uint32_t*)(DDR_BASE + 0x170)) /* DDR ZQ calibration control */ +#define DDR_WRLVL_CNTL *((volatile uint32_t*)(DDR_BASE + 0x174)) /* DDR write leveling control */ +#define DDR_SR_CNTR *((volatile uint32_t*)(DDR_BASE + 0x17C)) /* DDR Self Refresh Counter */ +#define DDR_SDRAM_RCW_1 *((volatile uint32_t*)(DDR_BASE + 0x180)) /* DDR Register Control Word 1 */ +#define DDR_SDRAM_RCW_2 *((volatile uint32_t*)(DDR_BASE + 0x184)) /* DDR Register Control Word 2 */ +#define DDR_WRLVL_CNTL_2 *((volatile uint32_t*)(DDR_BASE + 0x190)) /* DDR write leveling control 2 */ +#define DDR_WRLVL_CNTL_3 *((volatile uint32_t*)(DDR_BASE + 0x194)) /* DDR write leveling control 3 */ +#define DDR_SDRAM_RCW_3 *((volatile uint32_t*)(DDR_BASE + 0x1A0)) /* DDR Register Control Word 3 */ +#define DDR_SDRAM_RCW_4 *((volatile uint32_t*)(DDR_BASE + 0x1A4)) /* DDR Register Control Word 4 */ +#define DDR_SDRAM_RCW_5 *((volatile uint32_t*)(DDR_BASE + 0x1A8)) /* DDR Register Control Word 5 */ +#define DDR_SDRAM_RCW_6 *((volatile uint32_t*)(DDR_BASE + 0x1AC)) /* DDR Register Control Word 6 */ +#define DDR_SDRAM_MODE_3 *((volatile uint32_t*)(DDR_BASE + 0x200)) /* DDR SDRAM mode configuration 3 */ +#define DDR_SDRAM_MODE_4 *((volatile uint32_t*)(DDR_BASE + 0x204)) /* DDR SDRAM mode configuration 4 */ +#define DDR_SDRAM_MODE_5 *((volatile uint32_t*)(DDR_BASE + 0x208)) /* DDR SDRAM mode configuration 5 */ +#define DDR_SDRAM_MODE_6 *((volatile uint32_t*)(DDR_BASE + 0x20C)) /* DDR SDRAM mode configuration 6 */ +#define DDR_SDRAM_MODE_7 *((volatile uint32_t*)(DDR_BASE + 0x210)) /* DDR SDRAM mode configuration 7 */ +#define DDR_SDRAM_MODE_8 *((volatile uint32_t*)(DDR_BASE + 0x214)) /* DDR SDRAM mode configuration 8 */ +#define DDR_SDRAM_MODE_9 *((volatile uint32_t*)(DDR_BASE + 0x220)) /* DDR SDRAM mode configuration 9 */ +#define DDR_SDRAM_MODE_10 *((volatile uint32_t*)(DDR_BASE + 0x224)) /* DDR SDRAM mode configuration 10 */ +#define DDR_SDRAM_MODE_11 *((volatile uint32_t*)(DDR_BASE + 0x228)) /* DDR SDRAM mode configuration 11 */ +#define DDR_SDRAM_MODE_12 *((volatile uint32_t*)(DDR_BASE + 0x22C)) /* DDR SDRAM mode configuration 12 */ +#define DDR_SDRAM_MODE_13 *((volatile uint32_t*)(DDR_BASE + 0x230)) /* DDR SDRAM mode configuration 13 */ +#define DDR_SDRAM_MODE_14 *((volatile uint32_t*)(DDR_BASE + 0x234)) /* DDR SDRAM mode configuration 14 */ +#define DDR_SDRAM_MODE_15 *((volatile uint32_t*)(DDR_BASE + 0x238)) /* DDR SDRAM mode configuration 15 */ +#define DDR_SDRAM_MODE_16 *((volatile uint32_t*)(DDR_BASE + 0x23C)) /* DDR SDRAM mode configuration 16 */ +#define DDR_TIMING_CFG_8 *((volatile uint32_t*)(DDR_BASE + 0x250)) /* DDR SDRAM timing configuration 8 */ +#define DDR_SDRAM_CFG_3 *((volatile uint32_t*)(DDR_BASE + 0x260)) /* DDR SDRAM configuration 3 */ +#define DDR_DQ_MAP_0 *((volatile uint32_t*)(DDR_BASE + 0x400)) /* DDR DQ Map 0 */ +#define DDR_DQ_MAP_1 *((volatile uint32_t*)(DDR_BASE + 0x404)) /* DDR DQ Map 1 */ +#define DDR_DQ_MAP_2 *((volatile uint32_t*)(DDR_BASE + 0x408)) /* DDR DQ Map 2 */ +#define DDR_DQ_MAP_3 *((volatile uint32_t*)(DDR_BASE + 0x40C)) /* DDR DQ Map 3 */ +#define DDR_DDRDSR_1 *((volatile uint32_t*)(DDR_BASE + 0xB20)) /* DDR Debug Status Register 1 */ +#define DDR_DDRDSR_2 *((volatile uint32_t*)(DDR_BASE + 0xB24)) /* DDR Debug Status Register 2 */ +#define DDR_DDRCDR_1 *((volatile uint32_t*)(DDR_BASE + 0xB28)) /* DDR Control Driver Register 1 */ +#define DDR_DDRCDR_2 *((volatile uint32_t*)(DDR_BASE + 0xB2C)) /* DDR Control Driver Register 2 */ +#define DDR_MTCR *((volatile uint32_t*)(DDR_BASE + 0xD00)) /* Memory Test Control Register */ +#define DDR_MTPn(n) *((volatile uint32_t*)(DDR_BASE + 0xD20 + (n) * 4)) /* Memory Test Pattern Register */ +#define DDR_MTP0 *((volatile uint32_t*)(DDR_BASE + 0xD20)) /* Memory Test Pattern Register 0 */ +#define DDR_MT_ST_ADDR *((volatile uint32_t*)(DDR_BASE + 0xD64)) /* Memory Test Start Address */ +#define DDR_MT_END_ADDR *((volatile uint32_t*)(DDR_BASE + 0xD6C)) /* Memory Test End Address */ +#define DDR_ERR_DETECT *((volatile uint32_t*)(DDR_BASE + 0xE40)) /* Memory error detect */ +#define DDR_ERR_DISABLE *((volatile uint32_t*)(DDR_BASE + 0xE44)) /* Memory error disable */ +#define DDR_ERR_INT_EN *((volatile uint32_t*)(DDR_BASE + 0xE48)) /* Memory error interrupt enable */ +#define DDR_ERR_SBE *((volatile uint32_t*)(DDR_BASE + 0xE58)) /* Single-Bit ECC memory error management */ + +#define DDR_SDRAM_CFG_MEM_EN 0x80000000 /* SDRAM interface logic is enabled */ +#define DDR_SDRAM_CFG_BI 0x00000001 +#define DDR_SDRAM_CFG2_D_INIT 0x00000010 /* data initialization in progress */ +#define DDR_MEM_TEST_EN 0x80000000 /* Memory test enable */ +#define DDR_MEM_TEST_FAIL 0x00000001 /* Memory test fail */ +#define TEST_DDR_SIZE 1024 * 5 +#define TEST_DDR_OFFSET 0x10000000 + +/* MMU Access permission and shareability + Device mem encoding 0b0000dd00 + dd = 00, 01, 10, 11 + Nomral Mem encoding 0bxxxxiiii + xxxx = 00RW, 0100, 01RW, 10RW, 11RW, where RW = Outer Read/Write policy + iiii = 00RW, 0100, 01RW, 10RW, 11RW, where RW = Inner Read/Write policy + R or W is 0 for No alloc, 1 for alloc +*/ + #define ATTR_SH_IS (0x3 << 8) /* Inner Shareable */ + #define ATTR_SH_OS (0x2 << 8) /* Outer Shareable */ + #define ATTR_UXN (0x1 << 54) /* EL0 cannot execute */ + #define ATTR_PXN (0x1 << 53) /* EL1 cannot execute */ + #define ATTR_AF (0x1 << 10) /* Access Flag */ + #define ATTR_AP_RW_PL1 (0x1 << 6) /* EL1 Read-Write */ + #define ATTR_AP_RW_PL0 (0x0 << 6) /* EL0 Read-Write */ + #define ATTR_AP_RO_PL1 (0x5 << 6) /* EL1 Read-Only */ + #define ATTR_AP_RO_PL0 (0x4 << 6) /* EL0 Read-Only */ + #define ATTR_NS (0x1 << 5) /* Non-secure */ + #define ATTR_AP_RW (ATTR_AP_RW_PL1 | ATTR_AP_RW_PL0) + + /* Memory attribute MAIR reg cfg */ + #define ATTR_IDX_NORMAL_MEM 0 + #define MAIR_ATTR_NORMAL_MEM 0xFF /* Normal, Write-Back, Read-Write-Allocate */ + #define ATTR_IDX_DEVICE_MEM 1 + #define MAIR_ATTR_DEVICE_MEM 0x04 /* Device-nGnRnE */ + + #define ATTRIBUTE_DEVICE (ATTR_IDX_DEVICE_MEM << 2) | ATTR_AP_RW | ATTR_SH_IS + #define ATTRIBUTE_NORMAL_MEM (ATTR_IDX_NORMAL_MEM << 2) | ATTR_AP_RW | ATTR_SH_IS + +/* SPI interface */ +#define SPI_MCR(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x000)) +#define SPI_TCR(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x008)) +#define SPI_CTAR0(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x00C)) +#define SPI_CTAR1(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x010)) +#define SPI_SR(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x02C)) +#define SPI_RSER(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x030)) +#define SPI_PUSHR(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x034)) +#define SPI_POPR(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x038)) +#define SPI_TXFR0(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x03C)) +#define SPI_TXFR1(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x040)) +#define SPI_TXFR2(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x044)) +#define SPI_TXFR3(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x048)) +#define SPI_RXFR0(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x07C)) +#define SPI_RXFR1(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x080)) +#define SPI_RXFR2(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x084)) +#define SPI_RXFR3(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x088)) +#define SPI_CTARE0(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x11C)) +#define SPI_CTARE1(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x120)) +#define SPI_SREX(_n) *((volatile unsigned int*)(SPI_BASE(_n)+0x13C)) + +/* Configuration is a simple, 8-bit frame that is expected to be + * accessed with single byte transactions. + */ + +/* MCR config */ +/* Master, no frz, inactive CS high, flush FIFO, halt */ +#define SPI_MCR_MASTER_HALT 0x80010301ul +/* Master, no frz, inactive CS high, running */ +#define SPI_MCR_MASTER_RUNNING 0x80010000ul + +/* CTAR config*/ +/* no double baud, 8-bit frame, mode 00, MSB, default delays + * PBR=2, BR=32 for total divisor 64 + * 200MHz platform clock yields 3.125MHz SPI clk */ +#define SPI_CTAR_8_00MODE_64DIV 0x38000005 + +/* no double baud, 8-bit frame, mode 00, MSB, default delays + * PBR=2, BR=4 for total divisor 8 + * 200MHz platform clock yields 25MHz SPI clk */ +#define SPI_CTAR_8_00MODE_8DIV 0x38000001 + +/* SPI has TX/RX FIFO with limited depth, overwrite on overflow */ +#define SPI_FIFO_DEPTH 4 + +/* CMD/DATA FIFO entry*/ +/* no keep pcs asserted, use CTAR0, not EOQ, no clear TC, no parity*/ +#define SPI_PUSHR_LAST 0x00000000 +/* keep pcs asserted, use CTAR0, not EOQ, no clear TC, no parity*/ +#define SPI_PUSHR_CONT 0x80000000 +/* CS selection (0-3). Not all SPI interfaces have 4 CS's */ +#define SPI_PUSHR_PCS_SHIFT (16) +#define SPI_PUSHR_PCS(_n) ((1ul<<(_n)) << SPI_PUSHR_PCS_SHIFT) + +/* Status register bits*/ +#define SPI_SR_TCF (1ul << 31) +#define SPI_SR_TFFF (1ul << 25) +#define SPI_SR_RXCTR (0xFul << 4) + +#endif /* !NXP_LS1028A_H */ diff --git a/hal/nxp_ls1028a.ld b/hal/nxp_ls1028a.ld new file mode 100644 index 000000000..ac76670d3 --- /dev/null +++ b/hal/nxp_ls1028a.ld @@ -0,0 +1,111 @@ +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_vector_table) + +MEMORY +{ + /*The flash address range on LS1028A RDB is 0x20000000 - 0x23FFFFFF.*/ + FLASH (rx) : ORIGIN = @WOLFBOOT_ORIGIN@, LENGTH = @BOOTLOADER_PARTITION_SIZE@ + + /* DDR4 - 2GB */ + DRAM (rwx) : ORIGIN = 0x80001000 , LENGTH = 0xBFFFFFFF + + /* OCRAM 256K for startup RAM */ + OCRAM (rwx) : ORIGIN = 0x18000000, LENGTH = 256K +} + +SECTIONS +{ + PROVIDE (_DDR_ADDRESS = 0x80001000); + PROVIDE (_OCRAM_ADDRESS = 0x18000000); + PROVIDE (_FLASH_ADDRESS = @WOLFBOOT_ORIGIN@); + PROVIDE (_CORE_NUMBER = 0); + PROVIDE (_MEMORY_SIZE = LENGTH(OCRAM)); + PROVIDE (_FLASH_SIZE = LENGTH(FLASH)); + PROVIDE (_STACK_SIZE = 64K); + + .boot : + { + PROVIDE(_vector_table = .); + ._vector_table = .; + . = ALIGN(0x800); + KEEP(*(.vector_table)) + KEEP(*(.boot*)) + } > FLASH + + + /* Read-only sections, merged into text segment: */ + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.got : { *(.rela.got) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + + .text : + { + _start_text = .; + *(.text*) + *(.note.*) + . = ALIGN(8); + _end_text = .; + } > FLASH + + .rodata : + { + _rodata_start = .; + *(.rodata) + *(.rodata.*) + . = ALIGN(8); + _rodata_end = .; + } > FLASH + + PROVIDE(_stored_data = .); + + .data : + { + _start_data = .; + KEEP(*(.data .data.* .gnu.linkonce.d.*)) + . = ALIGN(8); + KEEP(*(.ramcode)) + . = ALIGN(8); + _end_data = .; + } > OCRAM AT > FLASH + + .bss : + { + _start_bss = .; + __bss_start__ = .; + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > OCRAM + + . = ALIGN(16); + .stack : + { + _start_stack = .; + . = . + _STACK_SIZE; + _end_stack = .; + } > OCRAM + + PROVIDE(_stack_base = .); +} \ No newline at end of file diff --git a/hal/nxp_p1021.ld b/hal/nxp_p1021.ld index 3058dcc99..9a15d112b 100644 --- a/hal/nxp_p1021.ld +++ b/hal/nxp_p1021.ld @@ -2,8 +2,8 @@ OUTPUT_ARCH( "powerpc" ) ENTRY( _reset ) -HEAP_SIZE = 4K; /* heap not used */ -STACK_SIZE = 128K; +_HEAP_SIZE = 4K; /* heap not used */ +_STACK_SIZE = 128K; MEMORY { @@ -85,6 +85,6 @@ PROVIDE(_start_heap = _end); /* If relocated to DDR already then use stack end from DDR */ /* If debugging and DDR is not ready, use L1 or L2 */ -PROVIDE(_end_stack = _end + HEAP_SIZE + STACK_SIZE ); +PROVIDE(_end_stack = _end + _HEAP_SIZE + _STACK_SIZE ); /* PROVIDE(_end_stack = ORIGIN(L1RAM) + (LENGTH(L1RAM)) ); */ /* PROVIDE(_end_stack = ORIGIN(L2RAM) + (LENGTH(L2RAM)) ); */ diff --git a/hal/spi/spi_drv_nxp.c b/hal/spi/spi_drv_nxp.c index 548b6b920..76fc75cc9 100644 --- a/hal/spi/spi_drv_nxp.c +++ b/hal/spi/spi_drv_nxp.c @@ -26,7 +26,8 @@ #include #include "spi_drv.h" -#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) +#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) || \ + defined(TARGET_nxp_ls1028a) #ifdef WOLFBOOT_TPM /* functions from nxp_p1021.c and nxp_t1024.c hal */ @@ -34,15 +35,29 @@ extern void hal_espi_init(uint32_t cs, uint32_t clock_hz, uint32_t mode); extern int hal_espi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz, int flags); extern void hal_espi_deinit(void); +#if defined(TARGET_nxp_ls1028a) +/* Functions from hal/nxp_ls1028a.c */ +extern void nxp_ls1028a_spi_init(unsigned int sel); +extern int nxp_ls1028a_spi_xfer(unsigned int sel, unsigned int cs, + const unsigned char *out, unsigned char *in, + unsigned int size, int cont); +extern void nxp_ls1028a_spi_deinit(unsigned int sel); +#endif + #include +static int initialized = 0; + void spi_init(int polarity, int phase) { - static int initialized = 0; if (!initialized) { initialized++; +#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) hal_espi_init(SPI_CS_TPM, TPM2_SPI_MAX_HZ, (polarity | (phase << 1))); +#elif defined(TARGET_nxp_ls1028a) + nxp_ls1028a_spi_init(SPI_SEL_TPM); +#endif } (void)polarity; (void)phase; @@ -50,12 +65,26 @@ void spi_init(int polarity, int phase) void spi_release(void) { - hal_espi_deinit(); + if (initialized) { + initialized--; + +#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) + hal_espi_deinit(); +#elif defined(TARGET_nxp_ls1028a) + nxp_ls1028a_spi_deinit(SPI_SEL_TPM); +#endif + + } } int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz, int flags) { +#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) return hal_espi_xfer(cs, tx, rx, sz, flags); +#elif defined(TARGET_nxp_ls1028a) + return nxp_ls1028a_spi_xfer(SPI_SEL_TPM, cs, tx, rx, sz, flags); +#endif + } #endif /* WOLFBOOT_TPM */ #endif /* TARGET_ */ diff --git a/hal/spi/spi_drv_nxp.h b/hal/spi/spi_drv_nxp.h index 826e04588..cb3fb4a78 100644 --- a/hal/spi/spi_drv_nxp.h +++ b/hal/spi/spi_drv_nxp.h @@ -29,4 +29,17 @@ #endif #endif +#if defined(TARGET_nxp_ls1028a) + +/* LS1028A SPI to the MikroBus uses SPI3 (sel is 2) and CS 0 */ +#ifndef SPI_SEL_TPM +#define SPI_SEL_TPM 2 +#endif + +#ifndef SPI_CS_TPM +#define SPI_CS_TPM 0 +#endif + +#endif + #endif /* !SPI_DRV_NXP_H_INCLUDED */ diff --git a/hal/zynq.ld b/hal/zynq.ld index ac37289a4..5ad5ee56d 100644 --- a/hal/zynq.ld +++ b/hal/zynq.ld @@ -11,7 +11,11 @@ _EL2_STACK_SIZE = DEFINED(_EL2_STACK_SIZE) ? _EL2_STACK_SIZE : 1024; /* Define Memories in the system */ MEMORY { + /* psu_ddr_0_MEM_0 : ORIGIN = 0x0, LENGTH = 0x7FF00000 */ psu_ddr_0_MEM_0 : ORIGIN = 0x40000000, LENGTH = 0x100000 + psu_ddr_1_MEM_0 : ORIGIN = 0x800000000, LENGTH = 0x80000000 + psu_ocm_ram_0_MEM_0 : ORIGIN = 0xFFFC0000, LENGTH = 0x40000 + psu_qspi_linear_0_MEM_0 : ORIGIN = 0xC0000000, LENGTH = 0x20000000 } @@ -21,6 +25,11 @@ ENTRY(_vector_table) /* Define the sections, and where they are mapped in memory */ SECTIONS { + + PROVIDE (_DDR_ADDRESS = 0x80001000); + PROVIDE (_OCRAM_ADDRESS = ORIGIN(psu_ocm_ram_0_MEM_0)); + PROVIDE (_MEMORY_SIZE = LENGTH(psu_ocm_ram_0_MEM_0)); + .text : { KEEP (*(.vectors)) *(.boot) @@ -302,5 +311,7 @@ _SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); __el0_stack = .; } > psu_ddr_0_MEM_0 +PROVIDE(_stack_base = .); + _end = .; } diff --git a/include/spi_drv.h b/include/spi_drv.h index 332f136a7..a7f9a8cc3 100644 --- a/include/spi_drv.h +++ b/include/spi_drv.h @@ -59,7 +59,8 @@ #include "hal/spi/spi_drv_nrf5340.h" #endif -#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) +#if defined(TARGET_nxp_p1021) || defined(TARGET_nxp_t1024) || \ + defined(TARGET_nxp_ls1028a) #include "hal/spi/spi_drv_nxp.h" #endif diff --git a/src/boot_aarch64.c b/src/boot_aarch64.c index 837e1838a..00628e6dd 100644 --- a/src/boot_aarch64.c +++ b/src/boot_aarch64.c @@ -25,17 +25,22 @@ #include "loader.h" #include "wolfboot/wolfboot.h" +/* Linker exported variables */ extern unsigned int __bss_start__; extern unsigned int __bss_end__; -static volatile unsigned int cpu_id; -extern unsigned int *END_STACK; +#ifndef NO_XIP +extern unsigned int _stored_data; +extern unsigned int _start_data; +extern unsigned int _end_data; +#endif extern void main(void); extern void gicv2_init_secure(void); -void boot_entry_C(void) +void boot_entry_C(void) { - register unsigned int *dst; + register unsigned int *dst, *src; + /* Initialize the BSS section to 0 */ dst = &__bss_start__; while (dst < (unsigned int *)&__bss_end__) { @@ -43,6 +48,21 @@ void boot_entry_C(void) dst++; } +#ifndef NO_XIP + /* Copy data section from flash to RAM if necessary */ + src = (unsigned int*)&_stored_data; + dst = (unsigned int*)&_start_data; + if (src != dst) { + while (dst < (unsigned int *)&_end_data) { + *dst = *src; + dst++; + src++; + } + } +#else + (void)src; +#endif + /* Run wolfboot! */ main(); } diff --git a/src/boot_aarch64_start.S b/src/boot_aarch64_start.S index 0d1494ba3..56017a8a1 100644 --- a/src/boot_aarch64_start.S +++ b/src/boot_aarch64_start.S @@ -1,6 +1,6 @@ /** * Aarch64 bootup - * Copyright (C) 2021 wolfSSL Inc. + * Copyright (C) 2024 wolfSSL Inc. * * This file is part of wolfBoot. * @@ -20,17 +20,70 @@ */ +/* Include target-specific defines here to override any AA64 defaults */ +#ifdef TARGET_nxp_ls1028a +#include "../hal/nxp_ls1028a.h" +#endif + +/* AARCH64 default configurations */ +#if !defined(AA64_TARGET_EL) +#define AA64_TARGET_EL 2 +#endif + +#if !defined(AA64GIC_VERSION) +#define AA64GIC_VERSION 2 +#endif + +#if (AA64GIC_VERSION==2) + #if !defined(AA64GICV2_GICD_BASE) + #define AA64GICV2_GICD_BASE 0xF9010000 + #endif + #if !defined(AA64_GICC_BASE) + #define AA64GICV2_GICC_BASE 0xF9020000 + #endif +#endif + + +/* CURRENT_EL ARMv8 Current Exception Level Register */ +#define CURRENT_EL_MASK (0x3 << 2) /* Current EL */ +#define CURRENT_EL_EL0 0x0 +#define CURRENT_EL_EL1 0x4 +#define CURRENT_EL_EL2 0x8 +#define CURRENT_EL_EL3 0xC + +/* ID_AA64PFR0_EL1 ARMv8 Processor Feature Register 0*/ +#define ID_AA64PFRO_EL3_MASK (0xF<<12) /* EL3 is implemented: 0x0000 no */ + /* 0x1000 AA64, 0x2000 AA64+AA32 */ +#define ID_AA64PFRO_EL2_MASK (0xF<<8) /* EL2 is implemented: 0x000 no */ + /* 0x100 AA64, 0x200 AA64+AA32 */ +#define ID_AA64PFRO_EL1_MASK (0xF<<4) /* EL1 is implemented: */ + /* 0x10 AA64, 0x20 AA64+AA32 */ +#define ID_AA64PFRO_EL0_MASK (0xF<<0) /* EL0 is implemented: */ + /* 0x1 AA64, 0x2 AA64+AA32 */ +#define ID_AA64PFRO_FGT_MASK (0xFull<<56) /* Fine Grained Traps: */ + /* 0x0 no, !0x0: yes */ + + +/* GICv2 Register Offsets */ +#ifndef GICD_BASE #define GICD_BASE 0xF9010000 +#endif #define GICD_CTLR 0x0000 #define GICD_TYPER 0x0004 #define GICD_SGIR 0x0F00 #define GICD_IGROUPRn 0x0080 +#ifndef GICC_BASE #define GICC_BASE 0xF9020000 +#endif #define GICC_PMR 0x0004 +.equ TZPCDECPROT0_SET_BASE, 0x02200804 +.equ TZPCDECPROT1_SET_BASE, 0x02200810 +.equ OCRAM_TZPC_ADDR , 0x02200000 + #ifndef USE_BUILTIN_STARTUP -.section ".boot" +.section ".boot", "ax" .global _vector_table _vector_table: mov x21, x0 // read ATAG/FDT address @@ -70,6 +123,10 @@ _vector_table: b 7b 8: mov sp, x1 // set stack pointer + +#ifdef CORTEX_A72 + bl init_A72 +#endif bl boot_entry_C // boot_entry_C never returns b 7b // go to sleep anyhow in case. #endif /* USE_BUILTIN_STARTUP */ @@ -99,3 +156,257 @@ gicv2_init_secure: str w0, [x1, #4] /* GICC_PMR */ 1: ret + + +#ifdef CORTEX_A72 +.global invalidate_ivac +invalidate_ivac: + ldr x0, =_OCRAM_ADDRESS + ldr x1, =_MEMORY_SIZE + add x1, x1, x0 + mrs x2, ctr_el0 + ubfx x4, x2, #16, #4 + mov x3, #4 + lsl x3, x3, x4 + sub x4, x3, #1 + bic x4, x0, x4 + inval_loop: + dc ivac, x4 + add x4, x4, x3 + cmp x4, x1 + blt inval_loop + dsb sy + ret + +.global disable_mmu +disable_mmu: + mrs x0, sctlr_el3 + bic x0, x0, x1 + msr sctlr_el3, x0 + isb + dsb sy + ret + +.global switch_el3_to_el2 +switch_el3_to_el2: + mov x0, #0x531 + msr scr_el3, x0 + msr cptr_el3, xzr /* Disable el3 traps */ + mov x0, #0x33ff + msr cptr_el2, x0 /* Disable el2 traps */ + mrs x0, sctlr_el2 + mov x1, #(1 << 0) | (1 << 2) | (1 << 12) + bic x0, x0, x1 + msr sctlr_el2, x0 + mrs x0, sctlr_el3 + bic x0, x0, x1 + msr sctlr_el3, x0 + bl invalidate_ivac + ldp x29, x30, [sp] + mrs x0, vbar_el3 + msr vbar_el2, x0 + mov x0, #0x3c9 + msr spsr_el3, x0 + msr elr_el3, x30 + ret + +.global cortex_a72_erratta +cortex_a72_erratta: + +/* Initalization code for NXP LS1028a (A72) */ +.global init_A72 +init_A72: + ldr x1, =_vector_table_el3 /* Initalize vec table */ + msr vbar_el3, x1 + +el3_state: + mrs x0, scr_el3 /* scr_el3 config */ + bic x0, x0, #(1 << 13) /* Trap WFE instruciton to EL3 off */ + bic x0, x0, #(1 << 12) /* Traps TWI ins to EL3 off */ + bic x0, x0, #(1 << 11) /* Traps EL1 access to physical secure timer to EL3 on */ + orr x0, x0, #(1 << 10) /* Next lower level is AArch64 */ + bic x0, x0, #(1 << 9) /* Secure state instuction fetches from non-secure memory are permitted */ + bic x0, x0, #(1 << 8) /* Hypervisor Call instruction disabled */ + bic x0, x0, #(1 << 7) /* Secure Monitor Call enabled */ + orr x0, x0, #0xf /* IRQ|FIQ|EA to EL3 */ + msr scr_el3, x0 + + mrs x0, sctlr_el3 /* sctlr_el3 config */ + bic x0, x0, #(1 << 19) /* Disable EL3 translation XN */ + bic x0, x0, #(1 << 12) /* Disable I cache */ + bic x0, x0, #(1 << 3) /* Disable SP Alignment check */ + bic x0, x0, #(1 << 2) /* Disable D cache */ + bic x0, x0, #(1 << 1) /* Disable Alignment check */ + bic x0, x0, #(1 << 0) /* Disable MMU */ + msr sctlr_el3, x0 + isb + +invalidate_cache: + msr csselr_el1, x0 + mrs x4, ccsidr_el1 /* read cache size */ + and x1, x4, #0x7 + and x1, x1, #0x4 /* cache line size */ + ldr x3, =0x7ff + and x2, x3, x4, lsr #13 /* number of cache sets */ + ldr x3, =0x3ff + and x3, x3, x4, lsr #3 /* cache associativity number */ + clz w4, w3 + mov x5, #0 +way_loop: + mov x6, #0 +set_loop: + lsl x7, x5, x4 + orr x7, x0, x7 + lsl x8, x6, x1 + orr x7, x7, x8 + dc cisw, x7 /* invalidate cache */ + add x6, x6, #1 + cmp x6, x2 + ble set_loop /* loop until all sets are invalidated */ + add x5, x5, #1 + cmp x5, x3 + ble way_loop /* loop until all ways are invalidated */ + msr cptr_el3, xzr + +init_stack: + ldr x0, =_stack_base /* Set and align stack */ + sub x0, x0, #16 + and x0, x0, #-16 + mov sp, x0 + ldr x1, =_STACK_SIZE + msr sp_el2, x0 + msr sp_el1, x0 + msr sp_el0, x0 + mov x29, 0 /* Setup an initial dummy frame with saved fp=0 and saved lr=0 */ + stp x29, x29, [sp, #-16]! + mov x29, sp + + bl invalidate_ivac + b boot_entry_C + +.global mmu_enable +mmu_enable: + tlbi alle3 /* Invalidate table entries */ + dsb sy + isb + + /* Set tcr reg */ + ldr x0, =0x0 + orr x0, x0, #24 /* Size of the memory region */ + orr x0, x0, #(1 << 17) /* PS 40 bit */ + orr x0, x0, #(1 << 16) /* TG0 4KB */ + orr x0, x0, #(2 << 12) /* SH0 Outer Shareable */ + orr x0, x0, #(1 << 10) /* normal outer WBWA cacheable */ + orr x0, x0, #(1 << 8) /* normal inner WBWA cacheable */ + msr tcr_el3, x0 + + ldr x1, =0x44E048E000098AA4 //0xFF440C0400 + msr mair_el3, x1 + + ldr x0, =ttb0_base + msr ttbr0_el3, x0 + + mrs x0, S3_1_c15_c2_1 + orr x0, x0, #(1 << 6) /* Must set SPMEN */ + msr S3_1_c15_c2_1, x0 + isb + + /* Set sctlr reg */ + mrs x0, sctlr_el3 + orr x1, x0, #(1 << 12) /* I - instruction cache enable */ + orr x1, x0, #(1 << 2) /* C - data & unified cache enable */ + orr x1, x0, #(1 << 0) /* M - MMU enable */ + msr sctlr_el3, x1 + + dsb sy + isb + ret + +/* Exception Vector Table EL3 */ +.balign 0x800 +.global _vector_table_el3 +_vector_table_el3: +el3_sp0_sync: + eret + +.balign 0x80 +el3_sp0_irq: + eret + +.balign 0x80 +el3_spi_fiq: + eret + +.balign 0x80 +el3_sp0_serror: + eret + +.balign 0x80 +el3_spx_sync: + eret + +.balign 0x80 +el3_spx_irq: + eret + +.balign 0x80 +el3_spx_fiq: + eret + +.balign 0x80 +el3_spx_serror: + eret + +.balign 0x80 +lower_el3_aarch64_sync: + eret + +.balign 0x80 +lower_el3_aarch64_irq: + eret + +.balign 0x80 +lower_el3_aarch64_fiq: + eret + +.balign 0x80 +lower_el3_aarch64_serror: + eret + + +/* Memory Table Macros */ +.macro PUT_64BIT_WORD high, low + .word \low + .word \high +.endm + +.macro TABLE_ENTRY PA, attributes +PUT_64BIT_WORD \attributes, \PA + 0x3 +.endm + +.macro BLOCK_1GB PA, attr_hi, attr_lo +PUT_64BIT_WORD \attr_hi, ((\PA) & 0xc0000000) | \attr_lo | 0x1 +.endm + +.macro BLOCK_2MB PA, attr_hi, attr_lo +PUT_64BIT_WORD \attr_hi, ((\PA) & 0xffe00000) | \attr_lo | 0x1 +.endm + +/* Note: In EL3/2 has direct physical to virutal mapping */ +.align 12 +.global ttb0_base +ttb0_base: +TABLE_ENTRY level1_pagetable, 0 +BLOCK_1GB 0x80000000, 0, 0x740 +BLOCK_1GB 0xC0000000, 0, 0x740 + +.align 12 +.global level1_pagetable +level1_pagetable: +.set ADDR, 0x0 +.rept 0x200 +BLOCK_2MB (ADDR << 20), 0, 0x74c +.set ADDR, ADDR + 2 +.endr + +#endif /* CORTEX_A72 */ diff --git a/test-app/AARCH64-ls1028a.ld b/test-app/AARCH64-ls1028a.ld new file mode 100644 index 000000000..c96342bbb --- /dev/null +++ b/test-app/AARCH64-ls1028a.ld @@ -0,0 +1,55 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = 256K + DRAM (rwx) : ORIGIN = 0x80001000 , LENGTH = 0xBFFFFFFF + OCRAM (rwx) : ORIGIN = 0x18020100, LENGTH = 128K +} + +ENTRY(main); + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.boot*)) + *(.text*) + *(.rodata*) + *(.note.*) + . = ALIGN(4); + _end_text = .; + } > OCRAM + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > OCRAM + + PROVIDE(_stored_data = .); + + .data : + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > OCRAM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > OCRAM + . = ALIGN(4); +} + +END_STACK = _start_text; diff --git a/test-app/Makefile b/test-app/Makefile index 4b05adc94..7be78c5a6 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -423,6 +423,10 @@ ifeq ($(TARGET),x86_fsp_qemu) LDFLAGS= endif +ifeq ($(TARGET),nxp_ls1028a) + LSCRIPT_TEMPLATE:=AARCH64-ls1028a.ld +endif + CFLAGS+=-I../lib/wolfssl diff --git a/test-app/app_nxp_ls1028a.c b/test-app/app_nxp_ls1028a.c new file mode 100644 index 000000000..886e514f7 --- /dev/null +++ b/test-app/app_nxp_ls1028a.c @@ -0,0 +1,116 @@ +/* app_nxp_ls1028a.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include "wolfboot/wolfboot.h" + +/* P1021 */ +#define CCSRBAR (0x1000000) +#define SYS_CLK (400000000) + +/* P1021 PC16552D Dual UART */ +#define BAUD_RATE 115200 +#define UART_SEL 0 /* select UART 0 or 1 */ + +#define UART_BASE(n) (0x21C0500 + (n * 100)) + +#define UART_RBR(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* receiver buffer register */ +#define UART_THR(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* transmitter holding register */ +#define UART_IER(n) *((volatile uint8_t*)(UART_BASE(n) + 1)) /* interrupt enable register */ +#define UART_FCR(n) *((volatile uint8_t*)(UART_BASE(n) + 2)) /* FIFO control register */ +#define UART_IIR(n) *((volatile uint8_t*)(UART_BASE(n) + 2)) /* interrupt ID register */ +#define UART_LCR(n) *((volatile uint8_t*)(UART_BASE(n) + 3)) /* line control register */ +#define UART_LSR(n) *((volatile uint8_t*)(UART_BASE(n) + 5)) /* line status register */ +#define UART_SCR(n) *((volatile uint8_t*)(UART_BASE(n) + 7)) /* scratch register */ + +/* enabled when UART_LCR_DLAB set */ +#define UART_DLB(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* divisor least significant byte register */ +#define UART_DMB(n) *((volatile uint8_t*)(UART_BASE(n) + 1)) /* divisor most significant byte register */ + +#define UART_FCR_TFR (0x04) /* Transmitter FIFO reset */ +#define UART_FCR_RFR (0x02) /* Receiver FIFO reset */ +#define UART_FCR_FEN (0x01) /* FIFO enable */ +#define UART_LCR_DLAB (0x80) /* Divisor latch access bit */ +#define UART_LCR_WLS (0x03) /* Word length select: 8-bits */ +#define UART_LSR_TEMT (0x40) /* Transmitter empty */ +#define UART_LSR_THRE (0x20) /* Transmitter holding register empty */ + +static void uart_init(void) +{ + /* calc divisor for UART + * example config values: + * clock_div, baud, base_clk 163 115200 300000000 + * +0.5 to round up + */ + uint32_t div = (((SYS_CLK / 2.0) / (16 * BAUD_RATE)) + 0.5); + + while (!(UART_LSR(UART_SEL) & UART_LSR_TEMT)) + ; + + /* set ier, fcr, mcr */ + UART_IER(UART_SEL) = 0; + UART_FCR(UART_SEL) = (UART_FCR_TFR | UART_FCR_RFR | UART_FCR_FEN); + + /* enable baud rate access (DLAB=1) - divisor latch access bit*/ + UART_LCR(UART_SEL) = (UART_LCR_DLAB | UART_LCR_WLS); + /* set divisor */ + UART_DLB(UART_SEL) = (div & 0xff); + UART_DMB(UART_SEL) = ((div >> 8) & 0xff); + /* disable rate access (DLAB=0) */ + UART_LCR(UART_SEL) = (UART_LCR_WLS); +} + +static void uart_write(const char* buf, uint32_t sz) +{ + uint32_t pos = 0; + while (sz-- > 0) { + while (!(UART_LSR(UART_SEL) & UART_LSR_THRE)) + ; + UART_THR(UART_SEL) = buf[pos++]; + } +} + +static const char* hex_lut = "0123456789abcdef"; + +__attribute__((section(".boot"))) +void main(void) +{ + int i = 0; + int j = 0; + int k = 0; + char snum[8]; + uint32_t bootver; + uint32_t updv; + + uart_write("Test App\n", 9); + + /* Wait for reboot */ + while(1) { + for (j=0; j<1000000; j++); + i++; + + uart_write("\r\n0x", 4); + for (k=0; k<8; k++) { + snum[7 - k] = hex_lut[(i >> 4*k) & 0xf]; + } + uart_write(snum, 8); + } +}