-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Useful for launching firmware on the coprocessor without requiring kernel support on the main BMC core. ``` root@bmc:~ # ./culvert coprocessor run 0xba000000 $((32 * 1024 * 1024)) < zephyr.bin ``` Yields the following output on UART11: ``` *** Booting Zephyr OS build v00.02.01 *** Hello World! ast2600_ssp_evb ``` Signed-off-by: Andrew Jeffery <[email protected]>
- Loading branch information
Showing
3 changed files
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright (C) 2024 Code Construct | ||
|
||
#include "bits.h" | ||
#include "compiler.h" | ||
#include "host.h" | ||
#include "log.h" | ||
#include "rev.h" | ||
#include "soc.h" | ||
#include "soc/scu.h" | ||
#include "soc/sdmc.h" | ||
|
||
#include <errno.h> | ||
#include <limits.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#define COPROC_CACHED_MEM_SIZE (16 * 1024 * 1024) | ||
#define COPROC_TOTAL_MEM_SIZE (32 * 1024 * 1024) | ||
|
||
#define SCU_COPROC_CTRL 0xa00 | ||
#define SCU_COPROC_CTRL_RESET_ASSERT BIT(1) | ||
#define SCU_COPROC_CTRL_EN BIT(0) | ||
|
||
#define SCU_COPROC_MEM_BASE 0xa04 | ||
#define SCU_COPROC_IMEM_LIMIT 0xa08 | ||
#define SCU_COPROC_DMEM_LIMIT 0xa0c | ||
#define SCU_COPROC_CACHE_RANGE 0xa40 | ||
#define SCU_COPROC_CACHE_1ST_16MB_EN BIT(0) | ||
|
||
int cmd_coprocessor(const char *name __unused, int argc, char *argv[]) | ||
{ | ||
const char *arg_subcmd, *arg_mem_base, *arg_mem_size; | ||
struct host _host, *host = &_host; | ||
unsigned long mem_base, mem_size; | ||
struct soc _soc, *soc = &_soc; | ||
struct soc_region dram; | ||
struct sdmc *sdmc; | ||
struct ahb *ahb; | ||
struct scu *scu; | ||
ssize_t src; | ||
char *endp; | ||
int rc; | ||
|
||
if (argc < 3) { | ||
loge("Not enough arguments for coprocessor command\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
arg_subcmd = argv[0]; | ||
arg_mem_base = argv[1]; | ||
arg_mem_size = argv[2]; | ||
|
||
if (strcmp("run", arg_subcmd)) { | ||
loge("Unknown coprocessor subcommand '%s'\n", arg_subcmd); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
errno = 0; | ||
mem_base = strtoul(arg_mem_base, &endp, 0); | ||
if (mem_base == ULONG_MAX && errno) { | ||
loge("Failed to parse coprocessor RAM base '%s': %d\n", arg_mem_base, errno); | ||
return EXIT_FAILURE; | ||
} else if (arg_mem_base == endp || *endp) { | ||
loge("Failed to parse coprocessor RAM base '%s'\n", arg_mem_base); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
errno = 0; | ||
mem_size = strtoul(arg_mem_size, &endp, 0); | ||
if (mem_size == ULONG_MAX && errno) { | ||
loge("Failed to parse coprocessor RAM size '%s': %d\n", arg_mem_size, errno); | ||
} else if (arg_mem_size == endp || *endp) { | ||
loge("Failed to parse coprocessor RAM size '%s'\n", arg_mem_size); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
if (mem_size != COPROC_TOTAL_MEM_SIZE) { | ||
loge("We currently only support assigning 32M of memory to the coprocessor\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
if ((rc = host_init(host, argc - 3, argv + 3)) < 0) { | ||
loge("Failed to initialise host interface: %d\n", rc); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
if (!(ahb = host_get_ahb(host))) { | ||
loge("Failed to acquire AHB interface\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_host; | ||
} | ||
|
||
if ((rc = soc_probe(soc, ahb)) < 0) { | ||
loge("Failed to probe SoC: %d\n", rc); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_host; | ||
} | ||
|
||
if (soc_generation(soc) != ast_g6) { | ||
loge("We currently only support the AST2600-series coprocessor\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
|
||
if (!(sdmc = sdmc_get(soc))) { | ||
loge("Failed to acquire SDRAM memory controller\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
|
||
if ((rc = sdmc_get_dram(sdmc, &dram))) { | ||
loge("Failed to locate DRAM: %d\n", rc); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
|
||
#if ULONG_MAX > UINT32_MAX | ||
if (mem_base > UINT32_MAX) { | ||
loge("Provided RAM base 0x%ux exceeds SoC physical address space\n", mem_base); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
#endif | ||
|
||
if (((mem_base + mem_size) & UINT32_MAX) < mem_base) { | ||
loge("Invalid RAM region provided for coprocessor\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
|
||
if (mem_base < dram.start || (mem_base + mem_size) > (dram.start + dram.length)) { | ||
loge("Ill-formed RAM region provided for coprocessor\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
|
||
if (!(scu = scu_get(soc))) { | ||
loge("Failed to acquire SCU driver\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_soc; | ||
} | ||
|
||
if ((rc = scu_writel(scu, SCU_COPROC_CTRL, 0)) < 0) { | ||
loge("Failed to disable coprocoessor: %d\n", rc); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
/* TODO: Verify firmware fits inside specified region, somehow? */ | ||
if ((src = soc_siphon_out(soc, mem_base, STDIN_FILENO)) < 0) { | ||
loge("Failed to load coprocessor firmware to provided region: %d\n", src); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
if (scu_writel(scu, SCU_COPROC_MEM_BASE, mem_base) || | ||
scu_writel(scu, SCU_COPROC_IMEM_LIMIT, | ||
mem_base + COPROC_CACHED_MEM_SIZE) || | ||
scu_writel(scu, SCU_COPROC_DMEM_LIMIT, mem_base + mem_size) || | ||
scu_writel(scu, SCU_COPROC_CACHE_RANGE, SCU_COPROC_CACHE_1ST_16MB_EN)) { | ||
loge("Failed to configure coprocessor control registers\n"); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
if ((rc = scu_writel(scu, SCU_COPROC_CTRL, SCU_COPROC_CTRL_RESET_ASSERT)) < 0) { | ||
loge("Failed to assert the coprocessor reset: %d", rc); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
if (usleep(1000) == -1) { | ||
loge("Coprocessor reset pre-delay failed: %d", -errno); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
if ((rc = scu_writel(scu, SCU_COPROC_CTRL, 0)) < 0) { | ||
loge("Failed to disable coprocessor: %d\n", rc); | ||
} | ||
|
||
if (usleep(1000) == -1) { | ||
loge("Coprocessor reset post-delay failed: %d", -errno); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
if ((rc = scu_writel(scu, SCU_COPROC_CTRL, SCU_COPROC_CTRL_EN)) < 0) { | ||
loge("Failed to start coprocessor: %d\n", rc); | ||
rc = EXIT_FAILURE; | ||
goto cleanup_scu; | ||
} | ||
|
||
rc = EXIT_SUCCESS; | ||
|
||
cleanup_scu: | ||
scu_put(scu); | ||
|
||
cleanup_soc: | ||
soc_destroy(soc); | ||
|
||
cleanup_host: | ||
host_destroy(host); | ||
|
||
return rc; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
src += files('console.c', | ||
'coprocessor.c', | ||
'debug.c', | ||
'devmem.c', | ||
'ilpc.c', | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters