am: add riscv64-rocket
This commit is contained in:
parent
b458a3ad58
commit
73596f368c
|
@ -7,6 +7,10 @@ ifeq ($(ISA), mips32)
|
||||||
CROSS_COMPILE = mips-linux-gnu-
|
CROSS_COMPILE = mips-linux-gnu-
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ISA), riscv64)
|
||||||
|
CROSS_COMPILE = riscv64-unknown-linux-gnu-
|
||||||
|
endif
|
||||||
|
|
||||||
AS = $(CROSS_COMPILE)gcc
|
AS = $(CROSS_COMPILE)gcc
|
||||||
CC = $(CROSS_COMPILE)gcc
|
CC = $(CROSS_COMPILE)gcc
|
||||||
CXX = $(CROSS_COMPILE)g++
|
CXX = $(CROSS_COMPILE)g++
|
||||||
|
@ -28,6 +32,12 @@ CXXFLAGS += $(CFLAGS_COMMON) -ffreestanding -fno-rtti -fno-exceptions
|
||||||
ASFLAGS += -march=mips32 -EL -mno-check-zero-division -O0 -mno-abicalls -fno-pic -fno-delayed-branch
|
ASFLAGS += -march=mips32 -EL -mno-check-zero-division -O0 -mno-abicalls -fno-pic -fno-delayed-branch
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ISA), riscv64)
|
||||||
|
CFLAGS_COMMON = -fno-pic -static -mcmodel=medany -fno-delete-null-pointer-checks -mabi=lp64 -march=rv64imac
|
||||||
|
CFLAGS += $(CFLAGS_COMMON)
|
||||||
|
CXXFLAGS += $(CFLAGS_COMMON) -ffreestanding -fno-rtti -fno-exceptions
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(ISA), x86)
|
ifeq ($(ISA), x86)
|
||||||
CFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386
|
CFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386
|
||||||
CXXFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386 -ffreestanding -fno-rtti -fno-exceptions
|
CXXFLAGS += -m32 -fno-pic -fno-builtin -fno-stack-protector -fno-omit-frame-pointer -march=i386 -ffreestanding -fno-rtti -fno-exceptions
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
# RISCV64-rocket
|
|
@ -0,0 +1,4 @@
|
||||||
|
start.o: start.S
|
||||||
|
riscv64-unknown-linux-gnu-gcc -mabi=lp64 -march=rv64imac -I$(AM_HOME)/am/arch/riscv64-rocket/include -fno-pic -ffunction-sections -MMD -c start.S -o start.o
|
||||||
|
|
||||||
|
-include start.d
|
|
@ -0,0 +1,15 @@
|
||||||
|
.section entry, "ax"
|
||||||
|
.globl _start
|
||||||
|
.type _start, @function
|
||||||
|
|
||||||
|
.extern fdt
|
||||||
|
|
||||||
|
_start:
|
||||||
|
la sp, stack_end
|
||||||
|
la t0, fdt
|
||||||
|
sw x11, (t0)
|
||||||
|
tail _trm_init
|
||||||
|
|
||||||
|
stack:
|
||||||
|
.skip 0x4000
|
||||||
|
stack_end:
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DIR=${AM_HOME}/am/arch/riscv64-rocket/img
|
||||||
|
DEST=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
bash -c "cd $DIR/boot && make"
|
||||||
|
|
||||||
|
riscv64-unknown-linux-gnu-ld --gc-sections -T $DIR/loader.ld -e _start -o $DEST $DIR/boot/start.o --start-group $@ --end-group
|
||||||
|
riscv64-unknown-linux-gnu-objdump -d $DEST > $DEST.txt
|
|
@ -0,0 +1,22 @@
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x80000000;
|
||||||
|
entry : { *(entry) }
|
||||||
|
.text : {
|
||||||
|
*(.text*)
|
||||||
|
}
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata*)
|
||||||
|
}
|
||||||
|
etext = .;
|
||||||
|
_etext = .;
|
||||||
|
.data : {
|
||||||
|
*(.data*)
|
||||||
|
}
|
||||||
|
edata = .;
|
||||||
|
_edata = .;
|
||||||
|
.bss : {
|
||||||
|
*(.bss*)
|
||||||
|
}
|
||||||
|
end = .;
|
||||||
|
_end = .;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Run with rocketchip project"
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef __ARCH_H__
|
||||||
|
#define __ARCH_H__
|
||||||
|
|
||||||
|
struct _RegSet {
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef __RISCV64_ROCKET__
|
||||||
|
#define __RISCV64_ROCKET__
|
||||||
|
|
||||||
|
#define MAX_HARTS 2
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,123 @@
|
||||||
|
#include <klib.h>
|
||||||
|
#include "fdt.h"
|
||||||
|
#include "riscv64-rocket.h"
|
||||||
|
|
||||||
|
static inline uint32_t bswap(uint32_t x)
|
||||||
|
{
|
||||||
|
uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
|
||||||
|
uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16;
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t *fdt_scan_helper(
|
||||||
|
uint32_t *lex,
|
||||||
|
const char *strings,
|
||||||
|
struct fdt_scan_node *node,
|
||||||
|
const struct fdt_cb *cb)
|
||||||
|
{
|
||||||
|
struct fdt_scan_node child;
|
||||||
|
struct fdt_scan_prop prop;
|
||||||
|
int last = 0;
|
||||||
|
|
||||||
|
child.parent = node;
|
||||||
|
// these are the default cell counts, as per the FDT spec
|
||||||
|
child.address_cells = 2;
|
||||||
|
child.size_cells = 1;
|
||||||
|
prop.node = node;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
switch (bswap(lex[0])) {
|
||||||
|
case FDT_NOP: {
|
||||||
|
lex += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FDT_PROP: {
|
||||||
|
assert (!last);
|
||||||
|
prop.name = strings + bswap(lex[2]);
|
||||||
|
prop.len = bswap(lex[1]);
|
||||||
|
prop.value = lex + 3;
|
||||||
|
if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); }
|
||||||
|
if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); }
|
||||||
|
lex += 3 + (prop.len+3)/4;
|
||||||
|
cb->prop(&prop, cb->extra);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FDT_BEGIN_NODE: {
|
||||||
|
uint32_t *lex_next;
|
||||||
|
if (!last && node && cb->done) cb->done(node, cb->extra);
|
||||||
|
last = 1;
|
||||||
|
child.name = (const char *)(lex+1);
|
||||||
|
if (cb->open) cb->open(&child, cb->extra);
|
||||||
|
lex_next = fdt_scan_helper(
|
||||||
|
lex + 2 + strlen(child.name)/4,
|
||||||
|
strings, &child, cb);
|
||||||
|
if (cb->close && cb->close(&child, cb->extra) == -1)
|
||||||
|
while (lex != lex_next) *lex++ = bswap(FDT_NOP);
|
||||||
|
lex = lex_next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FDT_END_NODE: {
|
||||||
|
if (!last && node && cb->done) cb->done(node, cb->extra);
|
||||||
|
return lex + 1;
|
||||||
|
}
|
||||||
|
default: { // FDT_END
|
||||||
|
if (!last && node && cb->done) cb->done(node, cb->extra);
|
||||||
|
return lex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb)
|
||||||
|
{
|
||||||
|
struct fdt_header *header = (struct fdt_header *)fdt;
|
||||||
|
|
||||||
|
// Only process FDT that we understand
|
||||||
|
if (bswap(header->magic) != FDT_MAGIC ||
|
||||||
|
bswap(header->last_comp_version) > FDT_VERSION) return;
|
||||||
|
|
||||||
|
const char *strings = (const char *)(fdt + bswap(header->off_dt_strings));
|
||||||
|
uint32_t *lex = (uint32_t *)(fdt + bswap(header->off_dt_struct));
|
||||||
|
|
||||||
|
fdt_scan_helper(lex, strings, 0, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fdt_size(uintptr_t fdt)
|
||||||
|
{
|
||||||
|
struct fdt_header *header = (struct fdt_header *)fdt;
|
||||||
|
|
||||||
|
// Only process FDT that we understand
|
||||||
|
if (bswap(header->magic) != FDT_MAGIC ||
|
||||||
|
bswap(header->last_comp_version) > FDT_VERSION) return 0;
|
||||||
|
return bswap(header->totalsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
|
||||||
|
{
|
||||||
|
*result = 0;
|
||||||
|
for (int cells = node->address_cells; cells > 0; --cells)
|
||||||
|
*result = (*result << 32) + bswap(*value++);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
|
||||||
|
{
|
||||||
|
*result = 0;
|
||||||
|
for (int cells = node->size_cells; cells > 0; --cells)
|
||||||
|
*result = (*result << 32) + bswap(*value++);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str)
|
||||||
|
{
|
||||||
|
const char *list = (const char *)prop->value;
|
||||||
|
const char *end = list + prop->len;
|
||||||
|
int index = 0;
|
||||||
|
while (end - list > 0) {
|
||||||
|
if (!strcmp(list, str)) return index;
|
||||||
|
++index;
|
||||||
|
list += strlen(list) + 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
#ifndef FDT_H
|
||||||
|
#define FDT_H
|
||||||
|
|
||||||
|
#define FDT_MAGIC 0xd00dfeed
|
||||||
|
#define FDT_VERSION 17
|
||||||
|
|
||||||
|
struct fdt_header {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t totalsize;
|
||||||
|
uint32_t off_dt_struct;
|
||||||
|
uint32_t off_dt_strings;
|
||||||
|
uint32_t off_mem_rsvmap;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t last_comp_version; /* <= 17 */
|
||||||
|
uint32_t boot_cpuid_phys;
|
||||||
|
uint32_t size_dt_strings;
|
||||||
|
uint32_t size_dt_struct;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FDT_BEGIN_NODE 1
|
||||||
|
#define FDT_END_NODE 2
|
||||||
|
#define FDT_PROP 3
|
||||||
|
#define FDT_NOP 4
|
||||||
|
#define FDT_END 9
|
||||||
|
|
||||||
|
struct fdt_scan_node {
|
||||||
|
const struct fdt_scan_node *parent;
|
||||||
|
const char *name;
|
||||||
|
int address_cells;
|
||||||
|
int size_cells;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_scan_prop {
|
||||||
|
const struct fdt_scan_node *node;
|
||||||
|
const char *name;
|
||||||
|
uint32_t *value;
|
||||||
|
int len; // in bytes of value
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_cb {
|
||||||
|
void (*open)(const struct fdt_scan_node *node, void *extra);
|
||||||
|
void (*prop)(const struct fdt_scan_prop *prop, void *extra);
|
||||||
|
void (*done)(const struct fdt_scan_node *node, void *extra); // last property was seen
|
||||||
|
int (*close)(const struct fdt_scan_node *node, void *extra); // -1 => delete the node + children
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scan the contents of FDT
|
||||||
|
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb);
|
||||||
|
uint32_t fdt_size(uintptr_t fdt);
|
||||||
|
|
||||||
|
// Extract fields
|
||||||
|
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
|
||||||
|
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
|
||||||
|
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found
|
||||||
|
|
||||||
|
// Setup memory+clint+plic
|
||||||
|
void query_mem(uintptr_t fdt);
|
||||||
|
void query_harts(uintptr_t fdt);
|
||||||
|
void query_plic(uintptr_t fdt);
|
||||||
|
void query_clint(uintptr_t fdt);
|
||||||
|
|
||||||
|
// Remove information from FDT
|
||||||
|
void filter_harts(uintptr_t fdt, unsigned long hart_mask);
|
||||||
|
void filter_plic(uintptr_t fdt);
|
||||||
|
void filter_compat(uintptr_t fdt, const char *compat);
|
||||||
|
|
||||||
|
// The hartids of available harts
|
||||||
|
extern uint64_t hart_mask;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <am.h>
|
||||||
|
|
||||||
|
void _ioe_init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------- cycles and uptime --------------------
|
||||||
|
|
||||||
|
static unsigned long riscv64_time = 0;
|
||||||
|
|
||||||
|
unsigned long _uptime(){
|
||||||
|
return riscv64_time ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------- video --------------------
|
||||||
|
|
||||||
|
|
||||||
|
_Screen _screen = {
|
||||||
|
.width = 0,
|
||||||
|
.height = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
void _draw_p(int x, int y, uint32_t p) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void _draw_sync() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------- keyboard --------------------
|
||||||
|
|
||||||
|
static inline int upevent(int e) { return e; }
|
||||||
|
static inline int downevent(int e) { return e | 0x8000; }
|
||||||
|
|
||||||
|
int _read_key(){
|
||||||
|
return _KEY_NONE;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
#include <am.h>
|
||||||
|
#include <klib.h>
|
||||||
|
#include "fdt.h"
|
||||||
|
|
||||||
|
uintptr_t fdt = 0;
|
||||||
|
static uintptr_t mem_size = 0;
|
||||||
|
|
||||||
|
extern char _end;
|
||||||
|
extern int main();
|
||||||
|
extern void uart_init(uintptr_t fdt);
|
||||||
|
extern void uart_send(uint8_t data);
|
||||||
|
|
||||||
|
_Area _heap = {
|
||||||
|
.start = &_end,
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////// MEMORY SCAN /////////////////////////////////////////
|
||||||
|
|
||||||
|
struct mem_scan {
|
||||||
|
int memory;
|
||||||
|
const uint32_t *reg_value;
|
||||||
|
int reg_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mem_open(const struct fdt_scan_node *node, void *extra)
|
||||||
|
{
|
||||||
|
struct mem_scan *scan = (struct mem_scan *)extra;
|
||||||
|
memset(scan, 0, sizeof(*scan));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_prop(const struct fdt_scan_prop *prop, void *extra)
|
||||||
|
{
|
||||||
|
struct mem_scan *scan = (struct mem_scan *)extra;
|
||||||
|
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "memory")) {
|
||||||
|
scan->memory = 1;
|
||||||
|
} else if (!strcmp(prop->name, "reg")) {
|
||||||
|
scan->reg_value = prop->value;
|
||||||
|
scan->reg_len = prop->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_done(const struct fdt_scan_node *node, void *extra)
|
||||||
|
{
|
||||||
|
struct mem_scan *scan = (struct mem_scan *)extra;
|
||||||
|
const uint32_t *value = scan->reg_value;
|
||||||
|
const uint32_t *end = value + scan->reg_len/4;
|
||||||
|
uintptr_t self = (uintptr_t)mem_done;
|
||||||
|
|
||||||
|
if (!scan->memory) return;
|
||||||
|
assert (scan->reg_value && scan->reg_len % 4 == 0);
|
||||||
|
|
||||||
|
while (end - value > 0) {
|
||||||
|
uint64_t base, size;
|
||||||
|
value = fdt_get_address(node->parent, value, &base);
|
||||||
|
value = fdt_get_size (node->parent, value, &size);
|
||||||
|
if (base <= self && self <= base + size) { mem_size = size; }
|
||||||
|
}
|
||||||
|
assert (end == value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void query_mem(uintptr_t fdt)
|
||||||
|
{
|
||||||
|
struct fdt_cb cb;
|
||||||
|
struct mem_scan scan;
|
||||||
|
|
||||||
|
memset(&cb, 0, sizeof(cb));
|
||||||
|
cb.open = mem_open;
|
||||||
|
cb.prop = mem_prop;
|
||||||
|
cb.done = mem_done;
|
||||||
|
cb.extra = &scan;
|
||||||
|
|
||||||
|
mem_size = 0;
|
||||||
|
fdt_scan(fdt, &cb);
|
||||||
|
assert (mem_size > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _putc(char ch) {
|
||||||
|
uart_send(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void puts(const char *s) {
|
||||||
|
for (const char *p = s; *p; p ++) {
|
||||||
|
_putc(*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _halt(int code) {
|
||||||
|
puts("Exited (");
|
||||||
|
if (code == 0) _putc('0');
|
||||||
|
else {
|
||||||
|
char buf[10], *p = buf + 9;
|
||||||
|
for (*p = 0; code; code /= 10) {
|
||||||
|
*(-- p) = '0' + code % 10;
|
||||||
|
}
|
||||||
|
puts(p);
|
||||||
|
}
|
||||||
|
puts(").\n");
|
||||||
|
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _trm_init() {
|
||||||
|
uart_init(fdt);
|
||||||
|
|
||||||
|
query_mem(fdt);
|
||||||
|
_heap.end = (void *)0x80000000 + mem_size;
|
||||||
|
|
||||||
|
int ret = main();
|
||||||
|
_halt(ret);
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <klib.h>
|
||||||
|
#include "fdt.h"
|
||||||
|
|
||||||
|
volatile uint8_t* uart_base_ptr;
|
||||||
|
|
||||||
|
#define UART_RX_FIFO_REG 0
|
||||||
|
#define UART_TX_FIFO_REG 0x4
|
||||||
|
#define UART_STAT_REG 0x8
|
||||||
|
#define UART_CTRL_REG 0xc
|
||||||
|
|
||||||
|
void uart_send(uint8_t data) {
|
||||||
|
// wait until THR empty
|
||||||
|
while((*(uart_base_ptr + UART_STAT_REG) & 0x08));
|
||||||
|
*(uart_base_ptr + UART_TX_FIFO_REG) = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_send_string(const char *str) {
|
||||||
|
while(*str != 0) {
|
||||||
|
uart_send(*(str++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_send_buf(const char *buf, const int32_t len) {
|
||||||
|
int32_t i;
|
||||||
|
for(i=0; i<len; i++) {
|
||||||
|
uart_send(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uart_recv() {
|
||||||
|
// check whether RBR has data
|
||||||
|
if(! (*(uart_base_ptr + UART_STAT_REG) & 0x01u)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return *(uart_base_ptr + UART_RX_FIFO_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IRQ triggered read
|
||||||
|
uint8_t uart_read_irq() {
|
||||||
|
return *(uart_base_ptr + UART_RX_FIFO_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check uart IRQ for read
|
||||||
|
uint8_t uart_check_read_irq() {
|
||||||
|
return (*(uart_base_ptr + UART_STAT_REG) & 0x01u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable uart read IRQ
|
||||||
|
void uart_enable_read_irq() {
|
||||||
|
*(uart_base_ptr + UART_CTRL_REG) = 0x0010u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable uart read IRQ
|
||||||
|
void uart_disable_read_irq() {
|
||||||
|
*(uart_base_ptr + UART_CTRL_REG) = 0x0000u;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uart_scan
|
||||||
|
{
|
||||||
|
int compat;
|
||||||
|
uint64_t reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void uart_open(const struct fdt_scan_node *node, void *extra)
|
||||||
|
{
|
||||||
|
struct uart_scan *scan = (struct uart_scan *)extra;
|
||||||
|
memset(scan, 0, sizeof(*scan));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uart_prop(const struct fdt_scan_prop *prop, void *extra)
|
||||||
|
{
|
||||||
|
struct uart_scan *scan = (struct uart_scan *)extra;
|
||||||
|
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,uart0")) {
|
||||||
|
scan->compat = 1;
|
||||||
|
} else if (!strcmp(prop->name, "reg")) {
|
||||||
|
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uart_done(const struct fdt_scan_node *node, void *extra)
|
||||||
|
{
|
||||||
|
struct uart_scan *scan = (struct uart_scan *)extra;
|
||||||
|
if (!scan->compat || !scan->reg || uart_base_ptr) return;
|
||||||
|
|
||||||
|
// Enable Rx/Tx channels
|
||||||
|
uart_base_ptr = (void*)scan->reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_init(uintptr_t fdt)
|
||||||
|
{
|
||||||
|
struct fdt_cb cb;
|
||||||
|
struct uart_scan scan;
|
||||||
|
|
||||||
|
memset(&cb, 0, sizeof(cb));
|
||||||
|
cb.open = uart_open;
|
||||||
|
cb.prop = uart_prop;
|
||||||
|
cb.done = uart_done;
|
||||||
|
cb.extra = &scan;
|
||||||
|
|
||||||
|
fdt_scan(fdt, &cb);
|
||||||
|
|
||||||
|
if(!uart_base_ptr) {
|
||||||
|
//uart_base_ptr = (void *)0x60000000;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
uart_base_ptr += read_const_csr(mhartid) * 0x10000;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// reset the receive FIFO and transmit FIFO
|
||||||
|
*(uart_base_ptr + UART_CTRL_REG) = 0x3;
|
||||||
|
}
|
Loading…
Reference in New Issue