Skip to content

Commit

Permalink
Add support for Odroid-C2 and Odroid-C4
Browse files Browse the repository at this point in the history
Signed-off-by: Ivan Velickovic <[email protected]>
  • Loading branch information
Ivan-Velickovic committed Feb 25, 2024
1 parent 006d8a3 commit 224132b
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 0 deletions.
26 changes: 26 additions & 0 deletions build_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,32 @@ class ConfigInfo:
"hello": Path("example/imx8mq_evk/hello")
}
),
BoardInfo(
name="odroidc2",
gcc_cpu="cortex-a53",
loader_link_address=0x20000000,
kernel_options={
"KernelPlatform": "odroidc2",
"KernelIsMCS": True,
"KernelArmExportPCNTUser": True,
},
examples={
"hello": Path("example/odroidc2/hello")
}
),
BoardInfo(
name="odroidc4",
gcc_cpu="cortex-a55",
loader_link_address=0x20000000,
kernel_options={
"KernelPlatform": "odroidc4",
"KernelIsMCS": True,
"KernelArmExportPCNTUser": True,
},
examples={
"timer": Path("example/odroidc4/timer")
}
),
)

SUPPORTED_CONFIGS = (
Expand Down
18 changes: 18 additions & 0 deletions docs/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,24 @@ Microkit produces a raw binary file, so when using U-Boot you must execute the i

=> go 0x40480000

## Odroid-C2

The HardKernel Odroid-C2 is an ARM SBC based on the Amlogic Meson S905 system-on-chip. It
should be noted that the Odroid-C2 is no longer available for purchase but its successor,
the Odroid-C4, is readily available at the time of writing.

Microkit produces a raw binary file, so when using U-Boot you must execute the image using:

=> go 0x20000000

## Odroid-C4

The HardKernel Odroid-C4 is an ARM SBC based on the Amlogic Meson S905X3 system-on-chip.

Microkit produces a raw binary file, so when using U-Boot you must execute the image using:

=> go 0x20000000

## TQMa8XQP 1GB

The TQMa8XQP is a system-on-module designed by TQ-Systems GmbH.
Expand Down
55 changes: 55 additions & 0 deletions example/odroidc2/hello/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#
# Copyright 2021, Breakaway Consulting Pty. Ltd.
#
# SPDX-License-Identifier: BSD-2-Clause
#
ifeq ($(strip $(BUILD_DIR)),)
$(error BUILD_DIR must be specified)
endif

ifeq ($(strip $(MICROKIT_SDK)),)
$(error MICROKIT_SDK must be specified)
endif

ifeq ($(strip $(MICROKIT_BOARD)),)
$(error MICROKIT_BOARD must be specified)
endif

ifeq ($(strip $(MICROKIT_CONFIG)),)
$(error MICROKIT_CONFIG must be specified)
endif

TOOLCHAIN := aarch64-none-elf

CPU := cortex-a55

CC := $(TOOLCHAIN)-gcc
LD := $(TOOLCHAIN)-ld
AS := $(TOOLCHAIN)-as
MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit

HELLO_OBJS := hello.o

BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)

IMAGES := hello.elf
CFLAGS := -mcpu=$(CPU) -mstrict-align -nostdlib -ffreestanding -g -O3 -Wall -Wno-unused-function -Werror -I$(BOARD_DIR)/include
LDFLAGS := -L$(BOARD_DIR)/lib
LIBS := -lmicrokit -Tmicrokit.ld

IMAGE_FILE = $(BUILD_DIR)/loader.img
REPORT_FILE = $(BUILD_DIR)/report.txt

all: $(IMAGE_FILE)

$(BUILD_DIR)/%.o: %.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: %.s Makefile
$(AS) -g -mcpu=$(CPU) $< -o $@

$(BUILD_DIR)/hello.elf: $(addprefix $(BUILD_DIR)/, $(HELLO_OBJS))
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

$(IMAGE_FILE) $(REPORT_FILE): $(addprefix $(BUILD_DIR)/, $(IMAGES)) hello.system
$(MICROKIT_TOOL) hello.system --search-path $(BUILD_DIR) --board $(MICROKIT_BOARD) --config $(MICROKIT_CONFIG) -o $(IMAGE_FILE) -r $(REPORT_FILE)
16 changes: 16 additions & 0 deletions example/odroidc2/hello/hello.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2021, Breakaway Consulting Pty. Ltd.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdint.h>
#include <microkit.h>

void init(void)
{
microkit_dbg_puts("hello, world\n");
}

void notified(microkit_channel ch)
{
}
11 changes: 11 additions & 0 deletions example/odroidc2/hello/hello.system
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2021, Breakaway Consulting Pty. Ltd.
SPDX-License-Identifier: BSD-2-Clause
-->
<system>
<protection_domain name="hello" priority="254">
<program_image path="hello.elf" />
</protection_domain>
</system>
55 changes: 55 additions & 0 deletions example/odroidc4/timer/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#
# Copyright 2021, Breakaway Consulting Pty. Ltd.
#
# SPDX-License-Identifier: BSD-2-Clause
#
ifeq ($(strip $(BUILD_DIR)),)
$(error BUILD_DIR must be specified)
endif

ifeq ($(strip $(MICROKIT_SDK)),)
$(error MICROKIT_SDK must be specified)
endif

ifeq ($(strip $(MICROKIT_BOARD)),)
$(error MICROKIT_BOARD must be specified)
endif

ifeq ($(strip $(MICROKIT_CONFIG)),)
$(error MICROKIT_CONFIG must be specified)
endif

TOOLCHAIN := aarch64-none-elf

CPU := cortex-a55

CC := $(TOOLCHAIN)-gcc
LD := $(TOOLCHAIN)-ld
AS := $(TOOLCHAIN)-as
MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit

TIMER_OBJS := timer.o

BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)

IMAGES := timer.elf
CFLAGS := -mcpu=$(CPU) -mstrict-align -nostdlib -ffreestanding -g -O3 -Wall -Wno-unused-function -Werror -I$(BOARD_DIR)/include
LDFLAGS := -L$(BOARD_DIR)/lib
LIBS := -lmicrokit -Tmicrokit.ld

IMAGE_FILE = $(BUILD_DIR)/loader.img
REPORT_FILE = $(BUILD_DIR)/report.txt

all: $(IMAGE_FILE)

$(BUILD_DIR)/%.o: %.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: %.s Makefile
$(AS) -g -mcpu=$(CPU) $< -o $@

$(BUILD_DIR)/timer.elf: $(addprefix $(BUILD_DIR)/, $(TIMER_OBJS))
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

$(IMAGE_FILE) $(REPORT_FILE): $(addprefix $(BUILD_DIR)/, $(IMAGES)) timer.system
$(MICROKIT_TOOL) timer.system --search-path $(BUILD_DIR) --board $(MICROKIT_BOARD) --config $(MICROKIT_CONFIG) -o $(IMAGE_FILE) -r $(REPORT_FILE)
145 changes: 145 additions & 0 deletions example/odroidc4/timer/timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright 2024, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <stdint.h>
#include <stdbool.h>
#include <microkit.h>

/*
* This is a very simple timer driver with the intention of showing
* how to do MMIO and handle interrupts in Microkit.
*/

uintptr_t timer_regs;

#define TIMER_IRQ_CH 0

#define TIMER_REG_START 0x140

#define TIMER_A_INPUT_CLK 0
#define TIMER_E_INPUT_CLK 8
#define TIMER_A_EN (1 << 16)
#define TIMER_A_MODE (1 << 12)

#define TIMESTAMP_TIMEBASE_SYSTEM 0b000
#define TIMESTAMP_TIMEBASE_1_US 0b001
#define TIMESTAMP_TIMEBASE_10_US 0b010
#define TIMESTAMP_TIMEBASE_100_US 0b011
#define TIMESTAMP_TIMEBASE_1_MS 0b100

#define TIMEOUT_TIMEBASE_1_US 0b00
#define TIMEOUT_TIMEBASE_10_US 0b01
#define TIMEOUT_TIMEBASE_100_US 0b10
#define TIMEOUT_TIMEBASE_1_MS 0b11

#define NS_IN_US 1000ULL
#define NS_IN_MS 1000000ULL

typedef struct {
uint32_t mux;
uint32_t timer_a;
uint32_t timer_b;
uint32_t timer_c;
uint32_t timer_d;
uint32_t unused[13];
uint32_t timer_e;
uint32_t timer_e_hi;
uint32_t mux1;
uint32_t timer_f;
uint32_t timer_g;
uint32_t timer_h;
uint32_t timer_i;
} meson_timer_reg_t;

typedef struct {
volatile meson_timer_reg_t *regs;
bool disable;
} meson_timer_t;

meson_timer_t timer;

static char hexchar(unsigned int v)
{
return v < 10 ? '0' + v : ('a' - 10) + v;
}

static void puthex64(uint64_t val)
{
char buffer[16 + 3];
buffer[0] = '0';
buffer[1] = 'x';
buffer[16 + 3 - 1] = 0;
for (unsigned i = 16 + 1; i > 1; i--) {
buffer[i] = hexchar(val & 0xf);
val >>= 4;
}
microkit_dbg_puts(buffer);
}

uint64_t meson_get_time()
{
uint64_t initial_high = timer.regs->timer_e_hi;
uint64_t low = timer.regs->timer_e;
uint64_t high = timer.regs->timer_e_hi;
if (high != initial_high) {
low = timer.regs->timer_e;
}

uint64_t ticks = (high << 32) | low;
uint64_t time = ticks * NS_IN_US;
return time;
}

void meson_set_timeout(uint16_t timeout, bool periodic)
{
if (periodic) {
timer.regs->mux |= TIMER_A_MODE;
} else {
timer.regs->mux &= ~TIMER_A_MODE;
}

timer.regs->timer_a = timeout;

if (timer.disable) {
timer.regs->mux |= TIMER_A_EN;
timer.disable = false;
}
}

void meson_stop_timer()
{
timer.regs->mux &= ~TIMER_A_EN;
timer.disable = true;
}

void init()
{
timer.regs = (void *)(timer_regs + TIMER_REG_START);

timer.regs->mux = TIMER_A_EN | (TIMESTAMP_TIMEBASE_1_US << TIMER_E_INPUT_CLK) |
(TIMEOUT_TIMEBASE_1_MS << TIMER_A_INPUT_CLK);

timer.regs->timer_e = 0;

// Have a timeout of 1 second, and have it be periodic so that it will keep recurring.
microkit_dbg_puts("Setting a timeout of 1 second.\n");
meson_set_timeout(1000, true);
}

void notified(microkit_channel ch)
{
switch (ch) {
case TIMER_IRQ_CH:
microkit_dbg_puts("Got timer interrupt!\n");
microkit_irq_ack(ch);
microkit_dbg_puts("Current time is: ");
puthex64(meson_get_time());
microkit_dbg_puts("\n");
break;
default:
microkit_dbg_puts("TIMER|ERROR: unexpected channel!\n");
}
}
15 changes: 15 additions & 0 deletions example/odroidc4/timer/timer.system
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2024, UNSW
SPDX-License-Identifier: BSD-2-Clause
-->
<system>
<memory_region name="timer" size="0x10_000" phys_addr="0xffd0f000" />

<protection_domain name="timer">
<program_image path="timer.elf" />
<map mr="timer" vaddr="0x2_000_000" perms="rw" cached="false" setvar_vaddr="timer_regs" />
<irq irq="42" id="0" trigger="edge" />
</protection_domain>
</system>
22 changes: 22 additions & 0 deletions loader/src/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,28 @@ static void putc(uint8_t ch)
while (!(*UART_REG(STAT) & STAT_TDRE)) { }
*UART_REG(TRANSMIT) = ch;
}
#elif defined(BOARD_odroidc2)
#define UART_BASE 0xc81004c0
#define UART_WFIFO 0x0
#define UART_STATUS 0xC
#define UART_TX_FULL (1 << 21)

static void putc(uint8_t ch)
{
while ((*UART_REG(UART_STATUS) & UART_TX_FULL));
*UART_REG(UART_WFIFO) = ch;
}
#elif defined(BOARD_odroidc4)
#define UART_BASE 0xff803000
#define UART_WFIFO 0x0
#define UART_STATUS 0xC
#define UART_TX_FULL (1 << 21)

static void putc(uint8_t ch)
{
while ((*UART_REG(UART_STATUS) & UART_TX_FULL));
*UART_REG(UART_WFIFO) = ch;
}
#else
#error Board not defined
#endif
Expand Down

0 comments on commit 224132b

Please sign in to comment.