ast27x0: Initialize and enable SSP/TSP using SCU with reserved-memory from DTB

This commit adds support for bringing up the SSP and TSP co-processors
on AST2700. The initialization and control logic are performed via SCU
register programming. Memory layout for firmware regions is retrieved
from reserved-memory nodes in the SPL device tree.

Features included:

- Add find_fmc_image() to locate FMC v2 image and extract payload range.
- Load and validate SPL DTB located after FMC payload.
- Parse reserved-memory nodes for SSP, TSP, ATF, OP-TEE, and IPC regions.
- Define struct mem_region and reserved_mem_info for memory layout data.
- Implement ssp_init() and ssp_enable() for SSP SCU setup and launch.
- Implement tsp_init() and tsp_enable() for TSP SCU setup and launch.
- Extend load_other_fit_images() to detect "sspfw" and "tspfw" images.
- Enable SSP/TSP after loading firmware from FIT image.
- Add SCU register definitions in struct ast2700_scu0.

Note: DTB is only used to retrieve memory layout for reserved regions.
The SSP and TSP initialization and activation are done via SCU registers.

Code adapted from:
https://github.com/AspeedTech-BMC/u-boot/blob/aspeed-master-v2023.10/board/aspeed/ibex_ast2700/ssp_tsp.c

Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
diff --git a/ast27x0/Makefile b/ast27x0/Makefile
index 3096884..5d13ba1 100644
--- a/ast27x0/Makefile
+++ b/ast27x0/Makefile
@@ -41,13 +41,13 @@
 CFLAGS		= -Os -Wall -Wextra -g -mcpu=cortex-a35 -fno-stack-protector \
 		  -no-pie -fno-pic \
 		  -I ./include -I ../lib/libfdt -I ../lib/libc/minimal/include
-CFLAGS      += -DGIT_VERSION=\"$(GIT_VERSION)\"
+CFLAGS		+= -DGIT_VERSION=\"$(GIT_VERSION)\"
 ASFLAGS		= $(CFLAGS) -Wa,-mcpu=cortex-a35
 LDSCRIPT	= bootrom.ld
 MAPFILE		= bootrom.map
 LDFLAGS		= -Wl,--build-id=none -static -nostdlib -T $(LDSCRIPT) -Wl,-Map=$(MAPFILE)
 
-OBJS		:= start.o image.o uart_aspeed.o uart_console.o \
+OBJS		:= start.o image.o uart_aspeed.o uart_console.o ssp_tsp.o \
 			../lib/libc/minimal/source/string/string.o \
 			../lib/libfdt/fdt.o ../lib/libfdt/fdt_ro.o
 
diff --git a/ast27x0/image.c b/ast27x0/image.c
index ab88ee7..d00e792 100644
--- a/ast27x0/image.c
+++ b/ast27x0/image.c
@@ -21,11 +21,11 @@
 #include <libfdt.h>
 #include <uart.h>
 #include <uart_console.h>
+#include <io.h>
+#include <image.h>
+#include <ssp_tsp.h>
 
 #define DEBUG 0
-#define DRAM_ADDR 0x400000000ULL
-#define FMCCS0  0x100000000ULL
-#define UART12  0x14C33B00
 
 #define FIT_SEARCH_START (FMCCS0)
 #define FIT_SEARCH_END   (FMCCS0 + 0x400000)
@@ -33,6 +33,9 @@
 
 extern void panic(const char *);
 
+static bool has_sspfw;
+static bool has_tspfw;
+
 /*
  * This global struct is explicitly initialized, so it is placed in the .data
  * section. The function pointer (uputc) is set to uart_aspeed_poll_out at
@@ -274,7 +277,8 @@
  * if some images do not define explicit load addresses in the FIT.
  */
 static void load_other_fit_images(const void *fit_blob, uint64_t uboot_end,
-                                  uint64_t *dest_addr)
+                                  uint64_t *dest_addr,
+                                  const struct reserved_mem_info *info)
 {
     uintptr_t data_offset;
     uint64_t load_addr;
@@ -316,6 +320,17 @@
             if (strcmp(name, "atf") == 0) {
                 *dest_addr = dram_addr;
             }
+
+            /* Init co-processor */
+            if (strcmp(name, "sspfw") == 0) {
+                ssp_init(dram_addr, info);
+                has_sspfw = true;
+            }
+
+            if (strcmp(name, "tspfw") == 0) {
+                tsp_init(dram_addr, info);
+                has_tspfw = true;
+            }
         } else if (strcmp(name, "fdt") == 0 && uboot_end) {
             /* fdt has no load address, fallback to uboot_end */
             load_addr = uboot_end;
@@ -366,17 +381,111 @@
     return NULL;
 }
 
+static int find_fmc_image(uint64_t start_addr, uint64_t end_addr,
+                          uint64_t search_step, struct fmc_img_info *info)
+{
+    struct ast_fmc_header *hdr;
+    uint32_t fmc_header_size;
+    uint32_t payload_size;
+    uint32_t total_size;
+    uint64_t addr;
+
+    if (info == NULL) {
+        return 0;
+    }
+
+    fmc_header_size = sizeof(struct ast_fmc_header);
+
+    for (addr = start_addr;
+         addr + fmc_header_size <= end_addr;
+         addr += search_step) {
+        hdr = (struct ast_fmc_header *)addr;
+
+        if (hdr->preamble.magic == FMC_HDR_MAGIC) {
+            payload_size = hdr->body.size;
+            total_size = fmc_header_size + payload_size;
+
+            if (payload_size > 0 && (addr + total_size) <= end_addr) {
+                info->payload_start = addr + fmc_header_size;
+                info->payload_end = ALIGN_UP(addr + total_size, search_step);
+                uprintf("Found valid FMC v%d image at 0x%lx (size: 0x%x)",
+                        hdr->preamble.version, addr, total_size);
+                uprintf(", next FIT search @ 0x%lx\n", info->payload_end);
+                return 1;
+            }
+        }
+    }
+
+    uprintf("No valid FMC image found in range 0x%lx - 0x%lx (step: 0x%lx)\n",
+            start_addr, end_addr, search_step);
+
+    return 0;
+}
+
+static void *load_dtb_after_fmc(uint64_t fmc_end, uint64_t end_addr)
+{
+    void *dram_dtb_addr = (void *)(uintptr_t)DRAM_ADDR;
+    const uint32_t *magic_ptr;
+    size_t copy_size;
+    uint64_t addr;
+
+    for (addr = ALIGN_UP(fmc_end, 4); addr + 4 < end_addr; addr += 4) {
+        /* Check for DTB magic number (aligned on 4-byte boundary) */
+        magic_ptr = (const uint32_t *)(uintptr_t)addr;
+        if (*magic_ptr != cpu_to_fdt32(FDT_MAGIC)) {
+            continue;
+        }
+
+        /* Copy from flash to DRAM for validation */
+        copy_size = end_addr - addr;
+        memcpy(dram_dtb_addr, (const void *)(uintptr_t)addr, copy_size);
+
+        /* Verify if the copied region is a valid DTB */
+        if (fdt_check_header(dram_dtb_addr) == 0) {
+            uprintf("Valid DTB found at 0x%lx, copied to 0x%lx\n",
+                    addr, (uint64_t)dram_dtb_addr);
+            return dram_dtb_addr;
+        } else {
+            uprintf("FDT_MAGIC at 0x%lx but invalid DTB header\n", addr);
+        }
+    }
+
+    uprintf("No valid DTB found between 0x%lx and 0x%lx\n", fmc_end, end_addr);
+    return NULL;
+}
+
 uint64_t load_boot_image(void)
 {
+    struct reserved_mem_info reservedinfo = {0};
+    struct fmc_img_info fmcinfo = {0};
+    uint64_t search_next_addr;
     uint64_t bl31_addr = 0;
     const void *fit_blob;
+    void *dtb_ptr = NULL;
     uint64_t uboot_end;
 
     uart_aspeed_init(UART12);
     uart_console_register(&ucons);
 
     print_build_info();
-    fit_blob = find_fit_image(FIT_SEARCH_START,
+
+    search_next_addr = FIT_SEARCH_START;
+
+    /* Find FMC image */
+    if (find_fmc_image(search_next_addr, FIT_SEARCH_END, FIT_SEARCH_STEP,
+                       &fmcinfo)) {
+        search_next_addr =  fmcinfo.payload_end;
+
+        /* Try to find and load a valid SPL DTB between FMC and U-Boot FIT */
+        dtb_ptr = load_dtb_after_fmc(fmcinfo.payload_start,
+                                     fmcinfo.payload_end);
+        if (dtb_ptr) {
+            get_reserved_memory(dtb_ptr, &reservedinfo);
+        }
+    }
+
+    /* Find U-Boot FIT imag */
+    fit_blob = find_fit_image(search_next_addr,
                               FIT_SEARCH_END,
                               FIT_SEARCH_STEP);
     if (!fit_blob) {
@@ -393,13 +502,23 @@
         panic("");
     }
 
-    load_other_fit_images(fit_blob, uboot_end, &bl31_addr);
+    load_other_fit_images(fit_blob, uboot_end, &bl31_addr, &reservedinfo);
 
     if (!bl31_addr) {
         uprintf("Error: BL31 (Trusted Firmware-A) not found, halting.\n");
         panic("");
     }
+
+    if (has_sspfw) {
+        ssp_enable();
+    }
+
+    if (has_tspfw) {
+        tsp_enable();
+    }
+
     uprintf("\nJumping to BL31 (Trusted Firmware-A) at 0x%lx\n\n",
             bl31_addr);
     return bl31_addr;
 }
+
diff --git a/ast27x0/include/image.h b/ast27x0/include/image.h
new file mode 100644
index 0000000..4fe3316
--- /dev/null
+++ b/ast27x0/include/image.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AST27X0_INCLUDE_IMAGE_H__
+#define __AST27X0_INCLUDE_IMAGE_H__
+
+#define DRAM_ADDR   0x400000000ULL
+#define FMCCS0      0x100000000ULL
+
+/* FMC v2 */
+/* ASTH */
+#define FMC_HDR_MAGIC 0x48545341
+#define ECC_SIGN_LEN  96
+#define LMS_SIGN_LEN  1620
+#define SHA_DGST_LEN  48
+
+struct hdr_preamble {
+    uint32_t magic;
+    uint32_t version;
+    uint32_t ecc_key_idx;
+    uint32_t lms_key_idx;
+    uint8_t ecc_sig[ECC_SIGN_LEN];
+    uint8_t lms_sig[LMS_SIGN_LEN];
+    uint32_t raz[15];
+};
+
+struct hdr_body {
+    uint32_t svn;
+    uint32_t size;
+    uint8_t dgst[SHA_DGST_LEN];
+    /* 712 bytes */
+    uint8_t reserved[178 * 4];
+};
+
+struct ast_fmc_header {
+    struct hdr_preamble preamble;
+    struct hdr_body body;
+} __attribute__((packed));
+
+struct fmc_img_info {
+    uint64_t payload_start;
+    uint64_t payload_end;
+};
+
+#endif /* __AST27X0_INCLUDE_IMAGE_H__ */
diff --git a/ast27x0/include/io.h b/ast27x0/include/io.h
index fab6546..6813940 100644
--- a/ast27x0/include/io.h
+++ b/ast27x0/include/io.h
@@ -27,4 +27,12 @@
 #define writel(value, addr) (*(volatile unsigned int *)(addr) = (unsigned int)(value))
 #define writeq(value, addr) (*(volatile unsigned long long *)(addr) = (unsigned long long)(value))
 
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+#define GENMASK(h, l) \
+    (((~0UL) >> (BITS_PER_LONG - ((h) - (l) + 1))) << (l))
+
+#define BIT(x) (1UL << (x))
+
+#define ALIGN_UP(x, align)  (((x) + ((align) - 1)) & ~((align) - 1))
+
 #endif /* __AST27X0_INCLUDE_IO_H__ */
diff --git a/ast27x0/include/ssp_tsp.h b/ast27x0/include/ssp_tsp.h
new file mode 100644
index 0000000..b93b26f
--- /dev/null
+++ b/ast27x0/include/ssp_tsp.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AST27X0_INCLUDE_SSP_TSP_H__
+#define __AST27X0_INCLUDE_SSP_TSP_H__
+
+#include <stdint.h>
+
+/* MAX visible range is 512M for SSP and TSP */
+#define MAX_I_D_ADDRESS (512 * 1024 * 1024)
+#define TCM_SIZE    (8 * 1024) /* 8KB */
+
+#define SSP_MEMORY_NODE     "/reserved-memory/ssp-memory"
+#define TSP_MEMORY_NODE     "/reserved-memory/tsp-memory"
+#define ATF_MEMORY_NODE     "/reserved-memory/trusted-firmware-a"
+#define OPTEE_MEMORY_NODE   "/reserved-memory/optee-core"
+#define IPC_SSP_MEMORY_NODE "/reserved-memory/ipc-ssp-share"
+
+/* SCU */
+#define ASPEED_CPU_SCU_BASE 0x12C02000
+
+struct ast2700_scu0 {
+    uint32_t rsv_0x11c[72];     /* 0x000 ~ 0x11C */
+    uint32_t ssp_ctrl_0;        /* 0x120 */
+    uint32_t ssp_ctrl_1;        /* 0x124 */
+    uint32_t ssp_ctrl_2;        /* 0x128 */
+    uint32_t ssp_ctrl_3;        /* 0x12C */
+    uint32_t ssp_ctrl_4;        /* 0x130 */
+    uint32_t ssp_ctrl_5;        /* 0x134 */
+    uint32_t ssp_ctrl_6;        /* 0x138 */
+    uint32_t rsv_0x13c[1];      /* 0x13C */
+    uint32_t ssp_tcm_base;      /* 0x140 */
+    uint32_t ssp_tcm_size;      /* 0x144 */
+    uint32_t ssp_ahb_base;      /* 0x148 */
+    uint32_t ssp_ahb_size;      /* 0x14c */
+    uint32_t ssp_memory_base;   /* 0x150 */
+    uint32_t ssp_memory_size;   /* 0x154 */
+    uint32_t rsv_0x158[2];      /* 0x158 ~ 0x15C */
+    uint32_t tsp_ctrl_0;        /* 0x160 */
+    uint32_t rsv_0x164[1];      /* 0x164 */
+    uint32_t tsp_ctrl_1;        /* 0x168 */
+    uint32_t tsp_ctrl_2;        /* 0x16C */
+    uint32_t tsp_ctrl_3;        /* 0x170 */
+    uint32_t tsp_ctrl_4;        /* 0x174 */
+    uint32_t tsp_ctrl_5;        /* 0x178 */
+    uint32_t rsv_0x17c[6];      /* 0x17C ~ 0x190 */
+    uint32_t tsp_remap_size;    /* 0x194 */
+};
+
+/* SSP control register 0 */
+#define SCU_CPU_SSP_TSP_RESET_STS               BIT(8)
+#define SCU_CPU_SSP_TSP_SRAM_SD                 BIT(7)
+#define SCU_CPU_SSP_TSP_SRAM_DSLP               BIT(6)
+#define SCU_CPU_SSP_TSP_SRAM_SLP                BIT(5)
+#define SCU_CPU_SSP_TSP_NIDEN                   BIT(4)
+#define SCU_CPU_SSP_TSP_DBGEN                   BIT(3)
+#define SCU_CPU_SSP_TSP_DBG_ENABLE              BIT(2)
+#define SCU_CPU_SSP_TSP_RESET                   BIT(1)
+#define SCU_CPU_SSP_TSP_ENABLE                  BIT(0)
+
+/* SSP control register 6 */
+#define SCU_CPU_SSP_TSP_CTRL_ICACHE_EN          BIT(1)
+#define SCU_CPU_SSP_TSP_CTRL_DCACHE_EN          BIT(0)
+
+struct mem_region {
+    uint64_t addr;
+    uint32_t size;
+};
+
+struct reserved_mem_info {
+    struct mem_region ssp;
+    struct mem_region tsp;
+    struct mem_region atf;
+    struct mem_region tee;
+    struct mem_region ipc_ssp;
+};
+
+void get_reserved_memory(const void *fdt_blob, struct reserved_mem_info *info);
+int ssp_init(uint64_t load_addr, const struct reserved_mem_info *info);
+int ssp_enable(void);
+int tsp_init(uint64_t load_addr, const struct reserved_mem_info *info);
+int tsp_enable(void);
+
+#endif /* __AST27X0_INCLUDE_SSP_TSP_H__ */
diff --git a/ast27x0/include/uart.h b/ast27x0/include/uart.h
index df16be7..567faf4 100644
--- a/ast27x0/include/uart.h
+++ b/ast27x0/include/uart.h
@@ -14,6 +14,8 @@
 #ifndef __AST27X0_INCLUDE_UART_H__
 #define __AST27X0_INCLUDE_UART_H__
 
+#define UART12  0x14C33B00
+
 /**
  * @brief UART Interface
  * @defgroup uart_interface UART Interface
diff --git a/ast27x0/ssp_tsp.c b/ast27x0/ssp_tsp.c
new file mode 100644
index 0000000..260858b
--- /dev/null
+++ b/ast27x0/ssp_tsp.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <io.h>
+#include <libfdt.h>
+#include <uart_console.h>
+#include <image.h>
+#include <ssp_tsp.h>
+
+void get_reserved_memory(const void *fdt_blob, struct reserved_mem_info *info)
+{
+    struct {
+        const char *path;
+        struct mem_region *region;
+    } nodes[] = {
+        { SSP_MEMORY_NODE,     &info->ssp       },
+        { TSP_MEMORY_NODE,     &info->tsp       },
+        { ATF_MEMORY_NODE,     &info->atf       },
+        { OPTEE_MEMORY_NODE,   &info->tee       },
+        { IPC_SSP_MEMORY_NODE, &info->ipc_ssp   },
+    };
+
+    const fdt32_t *reg;
+    const char *path;
+    int offset;
+    size_t i;
+
+    for (i = 0; i < sizeof(nodes) / sizeof(nodes[0]); i++) {
+        path = nodes[i].path;
+
+        offset = fdt_path_offset(fdt_blob, path);
+        if (offset < 0) {
+            uprintf("Cannot find node %s in the device tree.\n", path);
+            nodes[i].region->addr = 0;
+            nodes[i].region->size = 0;
+            continue;
+        }
+
+        reg = fdt_getprop(fdt_blob, offset, "reg", NULL);
+        if (!reg) {
+            uprintf("No reg property found in %s\n", path);
+            nodes[i].region->addr = 0;
+            nodes[i].region->size = 0;
+            continue;
+        }
+
+        nodes[i].region->addr = fdt32_to_cpu(reg[0]);
+        nodes[i].region->size = fdt32_to_cpu(reg[1]);
+
+        uprintf("[reserved] %s base: 0x%lx  size: 0x%lx\n", path,
+                nodes[i].region->addr, nodes[i].region->size);
+    }
+}
+
+int ssp_init(uint64_t load_addr, const struct reserved_mem_info *info)
+{
+    struct ast2700_scu0 *scu;
+    uint32_t reg_val;
+
+    scu = (struct ast2700_scu0 *)ASPEED_CPU_SCU_BASE;
+
+    reg_val = readl((void *)&scu->ssp_ctrl_0);
+    if (!(reg_val & SCU_CPU_SSP_TSP_RESET_STS)) {
+        return 0;
+    }
+
+    reg_val = SCU_CPU_SSP_TSP_NIDEN | SCU_CPU_SSP_TSP_DBGEN |
+              SCU_CPU_SSP_TSP_DBG_ENABLE | SCU_CPU_SSP_TSP_RESET;
+    writel(reg_val, (void *)&scu->ssp_ctrl_0);
+
+    /*
+     * SSP Memory Map:
+     * - 0x0000_0000 - 0x0587_FFFF: ssp_remap2 -> DRAM[load_addr]
+     * - 0x0588_0000 - 0x1FFF_DFFF: ssp_remap1 -> AHB -> DRAM[0]
+     * - 0x1FFF_E000 - 0x2000_0000: ssp_remap0 -> TCM (SSP stack)
+     *
+     * The SSP serves as the secure loader for TSP, ATF, OP-TEE, and U-Boot.
+     * Therefore, their load buffers must be visible to the SSP.
+     *
+     * - SSP remap entry #2 (ssp_remap2_base/size) maps the load buffers
+     *   for SSP, TSP, ATF, OP-TEE and IPC share memory. Ensure these buffers
+     *   are contiguous.
+     * - SSP remap entry #1 (ssp_remap1_base/size) maps the load buffer
+     *   for U-Boot at DRAM offset 0x0.
+     * - SSP remap entry #0 (ssp_remap0_base/size) maps TCM, which is used for
+     *   stack.
+     */
+    writel(0, (void *)&scu->ssp_memory_base);
+    reg_val = info->ssp.size + info->tsp.size + info->atf.size +
+              info->tee.size + info->ipc_ssp.size;
+    writel(reg_val, (void *)&scu->ssp_memory_size);
+
+    writel(reg_val, (void *)&scu->ssp_ahb_base);
+    writel(MAX_I_D_ADDRESS - reg_val - TCM_SIZE, (void *)&scu->ssp_ahb_size);
+
+    writel(MAX_I_D_ADDRESS - TCM_SIZE, (void *)&scu->ssp_tcm_base);
+    writel(TCM_SIZE, (void *)&scu->ssp_tcm_size);
+
+    /* Configure physical AHB remap: through H2M, mapped to SYS_DRAM_BASE */
+    writel((uint32_t)(DRAM_ADDR >> 4), (void *)&scu->ssp_ctrl_1);
+
+    /* Configure physical DRAM remap */
+    reg_val = (uint32_t)(load_addr >> 4);
+    writel(reg_val, (void *)&scu->ssp_ctrl_2);
+
+    /*
+     * For A1, the Cache region can only be enabled entirely;
+     * partial enabling is not supported.
+     */
+    writel(GENMASK(31, 0), (void *)&scu->ssp_ctrl_3);
+    writel(GENMASK(31, 0), (void *)&scu->ssp_ctrl_4);
+
+    /* Enable I and D cache as default */
+    writel(SCU_CPU_SSP_TSP_CTRL_ICACHE_EN | SCU_CPU_SSP_TSP_CTRL_DCACHE_EN,
+           (void *)&scu->ssp_ctrl_6);
+
+    return 0;
+}
+
+int ssp_enable(void)
+{
+    struct ast2700_scu0 *scu;
+    uint32_t reg_val;
+
+    scu = (struct ast2700_scu0 *)ASPEED_CPU_SCU_BASE;
+    reg_val = readl((void *)&scu->ssp_ctrl_0);
+    reg_val |= SCU_CPU_SSP_TSP_ENABLE | SCU_CPU_SSP_TSP_RESET;
+    writel(reg_val, (void *)&scu->ssp_ctrl_0);
+
+    return 0;
+}
+
+int tsp_init(uint64_t load_addr, const struct reserved_mem_info *info)
+{
+    struct ast2700_scu0 *scu;
+    uint32_t reg_val;
+
+    scu = (struct ast2700_scu0 *)ASPEED_CPU_SCU_BASE;
+
+    reg_val = readl((void *)&scu->tsp_ctrl_0);
+    if (!(reg_val & SCU_CPU_SSP_TSP_RESET_STS)) {
+        return 0;
+    }
+
+    reg_val = SCU_CPU_SSP_TSP_NIDEN | SCU_CPU_SSP_TSP_DBGEN |
+              SCU_CPU_SSP_TSP_DBG_ENABLE | SCU_CPU_SSP_TSP_RESET;
+    writel(reg_val, (void *)&scu->tsp_ctrl_0);
+
+    /* TSP 0x0000_0000 - 0x0200_0000 -> DRAM */
+    writel(info->tsp.size, (void *)&scu->tsp_remap_size);
+
+    /* Configure physical DRAM remap */
+    reg_val = (uint32_t)(load_addr >> 4);
+    writel(reg_val, (void *)&scu->tsp_ctrl_1);
+
+    /*
+     * For A1, the Cache region can only be enabled entirely;
+     * partial enabling is not supported.
+     */
+    writel(GENMASK(31, 0), (void *)&scu->tsp_ctrl_2);
+    writel(GENMASK(31, 0), (void *)&scu->tsp_ctrl_3);
+
+    /* Enable I and D cache as default */
+    writel(SCU_CPU_SSP_TSP_CTRL_ICACHE_EN | SCU_CPU_SSP_TSP_CTRL_DCACHE_EN,
+           (void *)&scu->tsp_ctrl_5);
+
+    return 0;
+}
+
+int tsp_enable(void)
+{
+    struct ast2700_scu0 *scu;
+    uint32_t reg_val;
+
+    scu = (struct ast2700_scu0 *)ASPEED_CPU_SCU_BASE;
+    reg_val = readl((void *)&scu->tsp_ctrl_0);
+    reg_val |= SCU_CPU_SSP_TSP_ENABLE | SCU_CPU_SSP_TSP_RESET;
+    writel(reg_val, (void *)&scu->tsp_ctrl_0);
+
+    return 0;
+}
+
diff --git a/ast27x0/uart_aspeed.c b/ast27x0/uart_aspeed.c
index 1ec4d7e..2a4990a 100644
--- a/ast27x0/uart_aspeed.c
+++ b/ast27x0/uart_aspeed.c
@@ -18,12 +18,6 @@
 #include <uart.h>
 #include <io.h>
 
-#define BITS_PER_LONG (sizeof(unsigned long) * 8)
-#define GENMASK(h, l) \
-    (((~0UL) >> (BITS_PER_LONG - ((h) - (l) + 1))) << (l))
-
-#define BIT(x) (1UL << (x))
-
 /* UART registers */
 #define UART_THR 0x00
 #define UART_DLL 0x00