- Now using C++

- Added missing boot image files for x-load and u-boot
This commit is contained in:
2013-07-04 12:06:57 +02:00
parent a3c9a865b1
commit 3cf5ff99ed
30 changed files with 1186 additions and 549 deletions

View File

@@ -1,19 +1,22 @@
CC=arm-none-eabi-gcc
#CC=arm-none-eabi-gcc
AS=arm-none-eabi-as
CXX=arm-none-eabi-g++
OBJCOPY=arm-none-eabi-objcopy
OBJDUMP=arm-none-eabi-objdump
CFLAGS=-march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -O1 -flto
LDFLAGS=
C_SRCS=cortexa8.c drv_omap35x_gpt.c main.c omap35x.c omap35x_intc.c omap35x_prcm.c uart.c syscall.c
#CFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -Og -flto
CXXFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=c++11 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -fstrict-enums -Wabi -Og -flto
LDFLAGS=-static
C_SRCS=drv_omap35x_gpt.c omap35x_intc.c omap35x_prcm.c syscall.c
CXX_SRCS=cortexa8.cc main.cc omap35x.cc uart.cc
S_SRCS=cortexa8_asm.s syscall_asm.s
OBJS=$(addprefix objs/,$(C_SRCS:.c=.o)) $(addprefix objs/,$(S_SRCS:.s=.o))
OBJS=$(addprefix objs/,$(C_SRCS:.c=.o)) $(addprefix objs/,$(CXX_SRCS:.cc=.o)) $(addprefix objs/,$(S_SRCS:.s=.o))
all: fw.img
fw: $(OBJS) fw.ld
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) -lc -T fw.ld
fw: $(OBJS) fw_cxx.ld
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJS) -lc -T fw_cxx.ld
fw.bin: fw
$(OBJCOPY) -O binary $< $@
@@ -29,15 +32,21 @@ qemu: beagle-nand.bin
qemu-system-arm -M beagle -m 256M -mtdblock beagle-nand.bin -nographic
objs/%.o: %.c
$(CC) $(CFLAGS) -c -MMD -MP -o $@ $<
$(CXX) $(CXXFLAGS) -c -MMD -MP -o $@ $<
@cp objs/$*.d objs/$*.P; rm -f objs/$*.d
objs/%.o: %.cc
$(CXX) $(CXXFLAGS) -c -MMD -MP -o $@ $<
@cp objs/$*.d objs/$*.P; rm -f objs/$*.d
objs/%.o: %.s
$(AS) $(ASOPTS) -o $@ $<
clean:
rm -f $(OBJS) fw fw.bin fw.img
rm -f $(OBJS) $(addprefix objs/,$(C_SRCS:.c=.P)) $(addprefix objs/,$(CXX_SRCS:.cc=.P)) fw fw.bin fw.img
.PSEUDO=all clean qemu
-include $(addprefix objs/,$(C_SRCS:.c=.P))
-include $(addprefix objs/,$(CXX_SRCS:.cc=.P))

View File

@@ -1,12 +1,13 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <cassert>
#include "uart.h"
#include "cortexa8.h"
#include "cortexa8.hh"
uint32_t cortexa8_read_cpuid(int reg) {
extern int _vect_table;
uint32_t cortexa8::read_cpuid(int reg) noexcept {
uint32_t rval;
switch(reg) {
case CORTEXA8_CPUID_MAINID:
@@ -36,28 +37,28 @@ uint32_t cortexa8_read_cpuid(int reg) {
return rval;
}
void cortexa8_enable_icache() {
void cortexa8::enable_icache() noexcept {
uint32_t reg;
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; orr %[reg], %[reg], #0x1000; mcr 15, 0, %[reg], c1, c0, 0; isb"
: [reg] "=r"(reg));
}
void cortexa8_enable_dcache() {
void cortexa8::enable_dcache() noexcept {
uint32_t reg;
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; orr %[reg], %[reg], #0x4; mcr 15, 0, %[reg], c1, c0, 0"
: [reg] "=r"(reg));
}
void cortexa8_disable_icache() {
void cortexa8::disable_icache() noexcept {
uint32_t reg;
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; bic %[reg], %[reg], #0x1000; mcr 15, 0, %[reg], c1, c0, 0; isb"
: [reg] "=r"(reg));
}
void cortexa8_disable_dcache() {
void cortexa8::disable_dcache() noexcept {
uint32_t reg;
__asm__ __volatile__ ("mrc 15, 0, %[reg], c1, c0, 0; bic %[reg], %[reg], #0x4; mcr 15, 0, %[reg], c1, c0, 0"
@@ -84,7 +85,7 @@ typedef struct {
static ptentry_section_t ttable1[4096] __attribute__((aligned(16384)));
void cortexa8_init_ttable() {
static void _init_ttable() noexcept {
// Create 1:1 translation table for entire address space with appropriate memory types
memset((void*)ttable1, 0, 16384);
@@ -133,8 +134,8 @@ void cortexa8_init_ttable() {
}
void cortexa8_init_mmu() {
cortexa8_init_ttable();
void cortexa8::init_mmu() noexcept {
_init_ttable();
// Set Translation Table base Ptr 0
uint32_t reg = ((uint32_t)ttable1) & 0xffffc000u;
@@ -164,8 +165,7 @@ void cortexa8_init_mmu() {
extern uint32_t __stack_excp;
extern uint32_t __stack_int;
extern void _vect_table;
void cortexa8_init_handlers() {
void cortexa8::init_handlers() noexcept {
// Set stack pointers
cortexa8_set_und_sp(&__stack_excp);
cortexa8_set_abt_sp(&__stack_excp);
@@ -179,8 +179,18 @@ void cortexa8_init_handlers() {
}
void cortexa8_excp_data_abt() __attribute__((interrupt ("ABORT")));
void cortexa8_excp_data_abt() {
// Default interrupt / exception handlers
extern "C" {
void _cortexa8_excp_data_abt() __attribute__((interrupt ("ABORT")));
void _cortexa8_excp_pf_abt() __attribute__((interrupt ("ABORT")));
void _cortexa8_excp_undef() __attribute__((interrupt ("UNDEF")));
void _cortexa8_syscall() __attribute__((interrupt ("SWI")));
void _cortexa8_unhandled_fiq() __attribute__((interrupt ("FIQ")));
}
void _cortexa8_excp_data_abt() {
uint32_t lr, dfar, dfsr;
__asm__ ("mov %[lr], lr; mrc 15, 0, %[dfsr], c5, c0, 0; mrc 15, 0, %[dfar], c6, c0, 0"
: [lr] "=r"(lr), [dfsr] "=r"(dfsr), [dfar] "=r"(dfar));
@@ -190,8 +200,7 @@ void cortexa8_excp_data_abt() {
while(1) {}
}
void cortexa8_excp_pf_abt() __attribute__((interrupt ("ABORT")));
void cortexa8_excp_pf_abt() {
void _cortexa8_excp_pf_abt() {
uint32_t lr, ifar, ifsr;
__asm__ ("mov %[lr], lr; mrc 15, 0, %[ifsr], c5, c0, 1; mrc 15, 0, %[ifar], c6, c0, 2"
: [lr] "=r"(lr), [ifsr] "=r"(ifsr), [ifar] "=r"(ifar));
@@ -201,8 +210,7 @@ void cortexa8_excp_pf_abt() {
while(1) {}
}
void cortexa8_excp_undef() __attribute__((interrupt ("UNDEF")));
void cortexa8_excp_undef() {
void _cortexa8_excp_undef() {
uint32_t lr, spsr;
__asm__ ("mov %[lr], lr"
: [lr] "=r"(lr));
@@ -213,12 +221,10 @@ void cortexa8_excp_undef() {
while(1) {}
}
void cortexa8_syscall() __attribute__((interrupt ("SWI")));
void cortexa8_syscall() {
uart_write("Syscall NYI\n", 12);
void _cortexa8_syscall() {
printf("Syscall NYI\n");
}
void cortexa8_unhandled_fiq() __attribute__((interrupt ("FIQ")));
void cortexa8_unhandled_fiq() {
uart_write("UNHANDLED FINTERRUPT\n", 21);
void _cortexa8_unhandled_fiq() {
printf("UNHANDLED FINTERRUPT\n");
}

View File

@@ -1,37 +0,0 @@
#ifndef _CORTEXA8_H_
#define _CORTEXA8_H_
#include <stdint.h>
#include <stdbool.h>
#define CORTEXA8_CPUID_MAINID 0
#define CORTEXA8_CPUID_CACHETYPE 1
#define CORTEXA8_CPUID_TLBTYPE 2
#define CORTEXA8_CPUID_PFR0 3
#define CORTEXA8_CPUID_PFR1 4
uint32_t cortexa8_read_cpuid(int reg);
void cortexa8_enable_icache();
void cortexa8_enable_dcache();
void cortexa8_disable_icache();
void cortexa8_disable_dcache();
void cortexa8_init_mmu();
void cortexa8_init_handlers();
// Implemented in cortexa8_asm.s
void cortexa8_ena_int();
void cortexa8_dis_int();
bool cortexa8_get_int();
void cortexa8_set_usr_sp(uint32_t *sp);
void cortexa8_set_abt_sp(uint32_t *sp);
void cortexa8_set_und_sp(uint32_t *sp);
void cortexa8_set_irq_sp(uint32_t *sp);
void cortexa8_set_fiq_sp(uint32_t *sp);
uint32_t cortexa8_get_spsr();
#endif

44
cortexa8.hh Normal file
View File

@@ -0,0 +1,44 @@
#ifndef _CORTEXA8_HH_
#define _CORTEXA8_HH_
#include <cstdint>
#define CORTEXA8_CPUID_MAINID 0
#define CORTEXA8_CPUID_CACHETYPE 1
#define CORTEXA8_CPUID_TLBTYPE 2
#define CORTEXA8_CPUID_PFR0 3
#define CORTEXA8_CPUID_PFR1 4
namespace cortexa8 {
uint32_t read_cpuid(int reg) noexcept;
void enable_icache() noexcept;
void enable_dcache() noexcept;
void disable_icache() noexcept;
void disable_dcache() noexcept;
void init_mmu() noexcept;
void init_handlers() noexcept;
}
// Implemented in cortexa8_asm.s
extern "C" {
void cortexa8_ena_int();
void cortexa8_dis_int();
bool cortexa8_get_int();
void cortexa8_set_usr_sp(void *sp);
void cortexa8_set_abt_sp(void *sp);
void cortexa8_set_und_sp(void *sp);
void cortexa8_set_irq_sp(void *sp);
void cortexa8_set_fiq_sp(void *sp);
uint32_t cortexa8_get_spsr();
}
#endif

View File

@@ -116,16 +116,16 @@ _vect_table:
/* Reset / unused */
nop
/* Undefined instruction */
b cortexa8_excp_undef
b _cortexa8_excp_undef
/* Supervisor call */
b cortexa8_syscall
b _cortexa8_syscall
/* Prefetch abort */
b cortexa8_excp_pf_abt
b _cortexa8_excp_pf_abt
/* Data abort */
b cortexa8_excp_data_abt
b _cortexa8_excp_data_abt
/* Unused */
nop
/* IRQ */
b omap35x_intc_handler
b _omap35x_intc_handler
/* FIQ */
b cortexa8_unhandled_fiq
b _cortexa8_unhandled_fiq

View File

@@ -1,60 +0,0 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include "drv_omap35x_gpt.h"
#include "omap35x_intc.h"
#define TIOCP_CFG 4
#define TISR 6
#define TIER 7
#define TWER 8
#define TCLR 9
#define TCRR 10
#define TLDR 11
#define TPIR 18
#define TNIR 19
int omap35x_gpt_init(omap35x_gpt_handle* handle, uint32_t base, int irq) {
assert(handle != NULL);
handle->base = (uint32_t*)base;
handle->irq = irq;
handle->handler = NULL;
handle->handler_data = NULL;
return 0;
}
void _omap35x_gpt_irqhandler(void *data);
int omap35x_gpt_ticktimer(omap35x_gpt_handle* handle, omap35x_intc_hfunc handler, void *data) {
assert(handle != NULL);
handle->base[TIOCP_CFG] = 0x215; // Clockactiviy = 2, emufree = 0, idlemode = 2 (smartidle), wakeup = ena, autoidle = 1
handle->base[TLDR] = -327;
handle->base[TCRR] = -327;
handle->base[TPIR] = 320000;
handle->base[TNIR] = -680000;
handle->handler = handler;
handle->handler_data = data;
omap35x_intc_register(handle->irq, &_omap35x_gpt_irqhandler, (void*)handle, 0);
handle->base[TCLR] = 0x3; // autoreload = 1, start = 1
handle->base[TIER] = 0x2; // Overflow int = enable
handle->base[TWER] = 0x2; // Overflow wakeup = enable
omap35x_intc_ena(handle->irq);
return 0;
}
void _omap35x_gpt_irqhandler(void *data) {
omap35x_gpt_handle *handle = (omap35x_gpt_handle*)data;
if(handle->handler != NULL)
handle->handler(handle->handler_data);
handle->base[TISR] = 0x2;
}

90
drv_omap35x_gpt.cc Normal file
View File

@@ -0,0 +1,90 @@
#include <cstdint>
#include <cstring>
#include <cassert>
#include <functional>
#include "drv_omap35x_gpt.hh"
#include "omap35x_intc.hh"
#include "util.hh"
#define TIOCP_CFG 4
#define TISR 6
#define TIER 7
#define TWER 8
#define TCLR 9
#define TCRR 10
#define TLDR 11
#define TPIR 18
#define TNIR 19
class OMAP35x_GPT_impl {
public:
OMAP35x_GPT_impl(uintptr_t base, int irq) : base_{base}, irq_{irq} {
}
~OMAP35x_GPT_impl() {
OMAP35x_intc::get().disable_int(irq_);
}
void ticktimer(int_handler_t handler) {
r_tiocp_cfg() = 0x215; // Clockactiviy = 2, emufree = 0, idlemode = 2 (smartidle), wakeup = ena, autoidle = 1
r_tldr() = -327;
r_tcrr() = -327;
r_tpir() = 320000;
r_tnir() = -680000;
handler_ = handler;
OMAP35x_intc::get().register_handler(irq_, std::bind(&OMAP35x_GPT_impl::irqhandler, this), 0);
r_tclr() = 0x3; // autoreload = 1, start = 1
r_tier() = 0x2; // Overflow int = enable
r_twer() = 0x2; // Overflow wakeup = enable
OMAP35x_intc::get().enable_int(irq_);
}
private:
void irqhandler() {
if(handler_)
handler_();
r_tisr() = 0x2;
}
uint32_t volatile& r_tidr() {return _reg32(base_, 0x0); }
uint32_t volatile& r_tiocp_cfg() {return _reg32(base_, 0x10); }
uint32_t volatile& r_tistat() {return _reg32(base_, 0x14); }
uint32_t volatile& r_tisr() {return _reg32(base_, 0x18); }
uint32_t volatile& r_tier() {return _reg32(base_, 0x1c); }
uint32_t volatile& r_twer() {return _reg32(base_, 0x20); }
uint32_t volatile& r_tclr() {return _reg32(base_, 0x24); }
uint32_t volatile& r_tcrr() {return _reg32(base_, 0x28); }
uint32_t volatile& r_tldr() {return _reg32(base_, 0x2c); }
uint32_t volatile& r_ttgr() {return _reg32(base_, 0x30); }
uint32_t volatile& r_twps() {return _reg32(base_, 0x34); }
uint32_t volatile& r_tmar() {return _reg32(base_, 0x38); }
uint32_t volatile& r_tcar1() {return _reg32(base_, 0x3c); }
uint32_t volatile& r_tsicr() {return _reg32(base_, 0x40); }
uint32_t volatile& r_tcar2() {return _reg32(base_, 0x44); }
uint32_t volatile& r_tpir() {return _reg32(base_, 0x48); }
uint32_t volatile& r_tnir() {return _reg32(base_, 0x4c); }
uint32_t volatile& r_tcvr() {return _reg32(base_, 0x50); }
uint32_t volatile& r_tocr() {return _reg32(base_, 0x54); }
uint32_t volatile& r_towr() {return _reg32(base_, 0x58); }
uintptr_t base_;
int irq_;
int_handler_t handler_;
};
OMAP35x_GPT::OMAP35x_GPT(uintptr_t base, int irq) : impl_{new OMAP35x_GPT_impl{base, irq}} {
}
OMAP35x_GPT::~OMAP35x_GPT() {
}
void OMAP35x_GPT::ticktimer(int_handler_t handler) {
impl_->ticktimer(handler);
}

View File

@@ -1,22 +0,0 @@
#ifndef _DRV_OMAP35X_GPT_H_
#define _DRV_OMAP35X_GPT_H_
#include <stdint.h>
#include "omap35x_intc.h"
typedef struct {
uint32_t* base;
int irq;
omap35x_intc_hfunc handler;
void *handler_data;
} omap35x_gpt_handle;
// Initialize a General-Purpose Timer
int omap35x_gpt_init(omap35x_gpt_handle* handle, uint32_t base, int irq);
// Configure the GPT 'handle' as the system tick timer (10 ms)
// The GPT must be GPTIMER1, GPTIMER2 or GPTIMER10 because the 1ms-Tick functionality is needed
int omap35x_gpt_ticktimer(omap35x_gpt_handle* handle, omap35x_intc_hfunc handler, void *data);
#endif

25
drv_omap35x_gpt.hh Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _DRV_OMAP35X_GPT_HH_
#define _DRV_OMAP35X_GPT_HH_
#include <cstdint>
#include <memory>
#include "omap35x_intc.hh"
class OMAP35x_GPT_impl;
class OMAP35x_GPT {
public:
// Initialize a General-Purpose Timer
OMAP35x_GPT(uintptr_t base, int irq);
~OMAP35x_GPT();
// Configure the GPT as the system tick timer (10 ms)
// The GPT must be GPTIMER1, GPTIMER2 or GPTIMER10 because the 1ms-Tick functionality is needed
void ticktimer(int_handler_t handler);
private:
std::unique_ptr<OMAP35x_GPT_impl> impl_;
};
#endif

208
fw_cxx.ld Normal file
View File

@@ -0,0 +1,208 @@
/* Default linker script, for normal executables */
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
/*SEARCH_DIR("/usr/arm-none-eabi/lib");*/
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x80008000)); . = SEGMENT_START("text-segment", 0x80008000);
/* .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) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rel.data.rel.ro : { *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) }
.rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rel.iplt :
{
PROVIDE_HIDDEN (__rel_iplt_start = .);
*(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
}
.rela.iplt :
{
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.rel.plt :
{
*(.rel.plt)
}
.rela.plt :
{
*(.rela.plt)
}*/
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
PROVIDE_HIDDEN (__exidx_end = .);
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
.data :
{
__data_start = . ;
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
__bss_start__ = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
_bss_end__ = . ; __bss_end__ = . ;
. = ALIGN(32 / 8);
. = ALIGN(32 / 8);
__end__ = . ;
_end = .; PROVIDE (end = .);
. = ALIGN(64);
.stack :
{
. = . + 0x200000; /* 2MiB stack should be enough... */
__stack = .;
*(.stack)
}
. = ALIGN(54);
. = . + 0x10000; /* 64KiB exception stack */
__stack_excp = .;
. = . + 0x10000; /* 64KiB interrupt stack */
__stack_int = .;
__heap_start = .; /* for _sbrk */
/* Rest until end of RAM is heap */
__heap_end = 0x90000000;
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

View File

@@ -4,38 +4,41 @@
#include <string.h>
#include <malloc.h>
#include "drv_omap35x_gpt.h"
#include "omap35x.h"
#include "omap35x_intc.h"
#include "omap35x_prcm.h"
#include "cortexa8.h"
#include "uart.h"
#include "drv_omap35x_gpt.hh"
#include "omap35x.hh"
#include "omap35x_intc.hh"
#include "omap35x_prcm.hh"
#include "cortexa8.hh"
#include "uart.hh"
static volatile uint32_t *const prcm_wkst_per = (uint32_t*)0x483070b0;
static volatile uint32_t tickctr = 0;
void tickfunc(void* data) {
void tickfunc() noexcept {
++tickctr;
*prcm_wkst_per = (1<<3); // Clear GPT2 wake bit
}
void setConsole(ICharacterDevice* newConsole);
int main(int argc, char* argv[]) {
// Enable caches
cortexa8_enable_icache();
cortexa8_enable_dcache();
cortexa8::enable_icache();
cortexa8::enable_dcache();
// Configure PRCM
omap35x_prcm_init();
OMAP35x_prcm prcm {0x48004000, 0x48306000};
// Configure interrrupt & exception handling
cortexa8_init_handlers();
omap35x_intc_init();
cortexa8::init_handlers();
OMAP35x_intc intc {0x48200000};
cortexa8_init_mmu();
cortexa8::init_mmu();
omap35x_prcm_enable();
prcm.enable_peripherals();
uart_init();
UART consoleUART {0x49020000, 74};
setConsole(&consoleUART);
// Enable interrupts
cortexa8_ena_int();
@@ -44,10 +47,9 @@ int main(int argc, char* argv[]) {
printf("5\n");
omap35x_gpt_handle gpt2;
omap35x_gpt_init(&gpt2, 0x49032000, 38);
OMAP35x_GPT gpt2{0x49032000, 38};
omap35x_gpt_ticktimer(&gpt2, &tickfunc, NULL);
gpt2.ticktimer(&tickfunc);
printf("6\n");
@@ -57,6 +59,8 @@ int main(int argc, char* argv[]) {
printf("%s", buf);
else
printf("Error\n");
if(strcmp(buf, "exit\n") == 0)
break;
}
while(1) {

View File

@@ -1,8 +1,9 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <cstdint>
#include <cstdio>
#include "omap35x.h"
#include "omap35x.hh"
using std::printf;
static volatile uint32_t *const omap35x_omap_sr = (uint32_t*)0x4800244c; // 1 word
static volatile uint32_t *const omap35x_idcode = (uint32_t*)0x4830a204; // 1 dword
@@ -46,7 +47,7 @@ void omap35x_print_chip_id() {
highfreq = true;
printf("%s %s %s Serial# %.8lx%.8lx%.8lx%.8lx\n",
omap_names[omapsr_idx], omap_ver[id_idx],
highfreq?"720 MHz":"600 MHz",
omap35x_die_id[3], omap35x_die_id[2], omap35x_die_id[1], omap35x_die_id[0]);
omap_names[omapsr_idx], omap_ver[id_idx],
highfreq?"720 MHz":"600 MHz",
omap35x_die_id[3], omap35x_die_id[2], omap35x_die_id[1], omap35x_die_id[0]);
}

View File

@@ -1,6 +0,0 @@
#ifndef _OMAP35X_H_
#define _OMAP35X_H_
void omap35x_print_chip_id();
#endif

6
omap35x.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _OMAP35X_HH_
#define _OMAP35X_HH_
void omap35x_print_chip_id();
#endif

View File

@@ -1,87 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "omap35x_intc.h"
#include "cortexa8.h"
static volatile uint32_t *const intc_sysconfig = (uint32_t*)0x48200010;
static volatile uint32_t *const intc_idle = (uint32_t*)0x48200050;
static volatile uint32_t *const intc_mir_clear0 = (uint32_t*)0x48200088;
static volatile uint32_t *const intc_mir_clear1 = (uint32_t*)0x482000a8;
static volatile uint32_t *const intc_mir_clear2 = (uint32_t*)0x482000c8;
static volatile uint32_t *const intc_mir_set0 = (uint32_t*)0x4820008c;
static volatile uint32_t *const intc_mir_set1 = (uint32_t*)0x482000ac;
static volatile uint32_t *const intc_mir_set2 = (uint32_t*)0x482000cc;
static volatile uint32_t *const intc_sir_irq = (uint32_t*)0x48200040;
static volatile uint32_t *const intc_control = (uint32_t*)0x48200048;
static volatile uint32_t *const intc_ilr = (uint32_t*)0x48200100; // 96 words
static omap35x_intc_hfunc handler_tbl[96];
static void* handler_data[96];
void omap35x_intc_init() {
// Interrupts should (still) be disabled from boot
assert(!cortexa8_get_int());
memset(handler_tbl, 0, sizeof(omap35x_intc_hfunc)*96);
*intc_sysconfig = 0x1; // Autoidle = 1
*intc_idle = 0x2; // Turbo = 1, Funcidle = 0
// Disable all ints
*intc_mir_set0 = 0xffffffff;
*intc_mir_set1 = 0xffffffff;
*intc_mir_set2 = 0xffffffff;
}
void omap35x_intc_register(int irq, omap35x_intc_hfunc handler, void *data, int prio) {
assert(irq >= 0 && irq <= 95);
assert(prio >= 0 && prio <= 63);
handler_tbl[irq] = handler;
handler_data[irq] = data;
intc_ilr[irq] = prio<<2;
}
void omap35x_intc_ena(int irq) {
assert(irq >= 0 && irq <= 95);
assert(handler_tbl[irq] != NULL);
int i = irq/32, j = irq%32;
if(i == 0)
*intc_mir_clear0 = (1<<j);
else if(i == 1)
*intc_mir_clear1 = (1<<j);
else //if(i == 2)
*intc_mir_clear2 = (1<<j);
}
void omap35x_intc_dis(int irq) {
assert(irq >= 0 && irq <= 95);
int i = irq/32, j = irq%32;
if(i == 0)
*intc_mir_set0 = (1<<j);
else if(i == 1)
*intc_mir_set1 = (1<<j);
else //if(i == 2)
*intc_mir_set2 = (1<<j);
}
void omap35x_intc_handler() __attribute__((interrupt ("IRQ")));
void omap35x_intc_handler() {
uint32_t sir = *intc_sir_irq;
int irq = sir&0x7f;
if(sir&0xffffff80) {
printf("WARNING: Spurious interrupt (%.8lx)\n", sir);
return;
}
assert(irq >= 0 && irq <= 95);
assert(handler_tbl[irq] != NULL);
handler_tbl[irq](handler_data[irq]);
*intc_control = 0x1;
__asm__ __volatile__ ("dsb");
}

130
omap35x_intc.cc Normal file
View File

@@ -0,0 +1,130 @@
#include <cstdio>
#include <cstring>
#include <cassert>
#include <array>
#include "omap35x_intc.hh"
#include "cortexa8.hh"
#include "util.hh"
extern "C" void _omap35x_intc_handler() __attribute__((interrupt ("IRQ")));
static OMAP35x_intc_impl* intc = nullptr;
class OMAP35x_intc_impl {
public:
OMAP35x_intc_impl(uintptr_t base) : base_{base} {
// Interrupts should (still) be disabled from boot
assert(!cortexa8_get_int());
// This is something like a singleton
assert(!intc);
intc = this;
r_sysconfig() = 0x1; // Autoidle = 1
r_idle() = 0x2; // Turbo = 1, Funcidle = 0
// Disable all ints
for(int i = 0;i <= 2;++i)
r_mir_set(i) = 0xffffffff;
}
void register_handler(int irq, int_handler_t const& handler, int prio) {
assert(irq >= 0 && irq <= 95);
assert(prio >= 0 && prio <= 63);
handler_tbl_[irq] = handler;
r_ilr(irq) = prio<<2;
}
void enable_int(int irq) {
assert(irq >= 0 && irq <= 95);
assert(handler_tbl_[irq]);
int i = irq/32, j = irq%32;
r_mir_clear(i) = (1<<j);
}
void disable_int(int irq) {
assert(irq >= 0 && irq <= 95);
int i = irq/32, j = irq%32;
r_mir_set(i) = (1<<j);
}
private:
friend void _omap35x_intc_handler();
void handler() {
uint32_t sir = r_sir_irq();
int irq = sir&0x7f;
if(sir&0xffffff80) {
printf("WARNING: Spurious interrupt (%.8lx)\n", sir);
return;
}
assert(irq >= 0 && irq <= 95);
assert(handler_tbl_[irq]);
handler_tbl_[irq]();
r_control() = 0x1;
__asm__ __volatile__ ("dsb");
}
uint32_t volatile& r_sysconfig() {return _reg32(base_, 0x10); }
uint32_t volatile& r_sysstatus() {return _reg32(base_, 0x14); }
uint32_t volatile& r_sir_irq() {return _reg32(base_, 0x40); }
uint32_t volatile& r_sir_fiq() {return _reg32(base_, 0x44); }
uint32_t volatile& r_control() {return _reg32(base_, 0x48); }
uint32_t volatile& r_protection() {return _reg32(base_, 0x4c); }
uint32_t volatile& r_idle() {return _reg32(base_, 0x50); }
uint32_t volatile& r_irq_priority() {return _reg32(base_, 0x60); }
uint32_t volatile& r_fiq_priority() {return _reg32(base_, 0x64); }
uint32_t volatile& r_threshold() {return _reg32(base_, 0x68); }
uint32_t volatile& r_itr(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x80+0x20*n); }
uint32_t volatile& r_mir(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x84+0x20*n); }
uint32_t volatile& r_mir_clear(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x88+0x20*n); }
uint32_t volatile& r_mir_set(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x8c+0x20*n); }
uint32_t volatile& r_isr_set(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x90+0x20*n); }
uint32_t volatile& r_isr_clear(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x94+0x20*n); }
uint32_t volatile& r_pending_irq(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x98+0x20*n); }
uint32_t volatile& r_pending_fiq(int n) {assert(n >= 0 && n <= 2); return _reg32(base_, 0x9c+0x20*n); }
uint32_t volatile& r_ilr(int m) {assert(m >= 0 && m <= 95); return _reg32(base_, 0x100+0x4*m); }
uintptr_t base_;
std::array<int_handler_t, 96> handler_tbl_;
};
void _omap35x_intc_handler() {
if(intc)
intc->handler();
}
OMAP35x_intc* OMAP35x_intc::instance_ = nullptr;
OMAP35x_intc::OMAP35x_intc(uintptr_t base) : impl_{new OMAP35x_intc_impl{base}} {
assert(!instance_);
instance_ = this;
}
OMAP35x_intc::~OMAP35x_intc() {
}
void OMAP35x_intc::register_handler(int irq, int_handler_t const& handler, int prio) {
impl_->register_handler(irq, handler, prio);
}
void OMAP35x_intc::enable_int(int irq) {
impl_->enable_int(irq);
}
void OMAP35x_intc::disable_int(int irq) {
impl_->disable_int(irq);
}
OMAP35x_intc& OMAP35x_intc::get() {
assert(instance_);
return *instance_;
}

View File

@@ -1,13 +0,0 @@
#ifndef OMAP35X_INTC_H
#define OMAP35X_INTC_H
typedef void (*omap35x_intc_hfunc)(void*);
void omap35x_intc_init();
void omap35x_intc_register(int irq, omap35x_intc_hfunc handler, void* data, int prio);
void omap35x_intc_ena(int irq);
void omap35x_intc_dis(int irq);
#endif

28
omap35x_intc.hh Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _OMAP35X_INTC_HH_
#define _OMAP35X_INTC_HH_
#include <functional>
#include <memory>
#include <cstdint>
using int_handler_t = std::function<void (void)>;
class OMAP35x_intc_impl;
class OMAP35x_intc {
public:
OMAP35x_intc(uintptr_t base);
~OMAP35x_intc();
void register_handler(int irq, int_handler_t const& handler, int prio);
void enable_int(int irq);
void disable_int(int irq);
static OMAP35x_intc& get();
private:
std::unique_ptr<OMAP35x_intc_impl> impl_;
static OMAP35x_intc* instance_;
};
#endif

View File

@@ -1,88 +0,0 @@
#include <stdint.h>
#include <stdio.h>
static volatile uint32_t *const prcm_clkstctrl_iva2 = (uint32_t*)0x48004048;
static volatile uint32_t *const prcm_wkdep_iva2 = (uint32_t*)0x483060c8;
static volatile uint32_t *const prcm_pwstctrl_iva2 = (uint32_t*)0x483060e0;
static volatile uint32_t *const prcm_clkstctrl_core = (uint32_t*)0x48004a48;
static volatile uint32_t *const prcm_fclken_per = (uint32_t*)0x48005000;
static volatile uint32_t *const prcm_iclken_per = (uint32_t*)0x48005010;
static volatile uint32_t *const prcm_autoidle_per = (uint32_t*)0x48005030;
static volatile uint32_t *const prcm_clksel_per = (uint32_t*)0x48005040;
static volatile uint32_t *const prcm_sleepdep_per = (uint32_t*)0x48005044;
static volatile uint32_t *const prcm_clkstctrl_per = (uint32_t*)0x48005048;
static volatile uint32_t *const prcm_wken_per = (uint32_t*)0x483070a0;
static volatile uint32_t *const prcm_mpugrpsel_per = (uint32_t*)0x483070a4;
static volatile uint32_t *const prcm_wkst_per = (uint32_t*)0x483070b0;
static volatile uint32_t *const prcm_clkstctrl_mpu = (uint32_t*)0x48004948;
static volatile uint32_t *const prcm_fclken_dss = (uint32_t*)0x48004e00;
static volatile uint32_t *const prcm_iclken_dss = (uint32_t*)0x48004e10;
static volatile uint32_t *const prcm_clkstctrl_dss = (uint32_t*)0x48004e48;
static volatile uint32_t *const prcm_wkdep_dss = (uint32_t*)0x48306ec8;
static volatile uint32_t *const prcm_pwstctrl_dss = (uint32_t*)0x48306ee0;
static volatile uint32_t *const prcm_clkstctrl_cam = (uint32_t*)0x48004f48;
static volatile uint32_t *const prcm_wkdep_cam = (uint32_t*)0x48306fc8;
static volatile uint32_t *const prcm_pwstctrl_cam = (uint32_t*)0x48306fe0;
static volatile uint32_t *const prcm_clkstctrl_neon = (uint32_t*)0x48005348;
static volatile uint32_t *const prcm_clkstctrl_usbhost = (uint32_t*)0x48005448;
static volatile uint32_t *const prcm_wkdep_usbhost = (uint32_t*)0x483074c8;
static volatile uint32_t *const prcm_pwstctrl_usbhost = (uint32_t*)0x483074e0;
void omap35x_prcm_init() {
// Setup IVA2 domain (unused, disable)
*prcm_clkstctrl_iva2 = 0x3;
*prcm_wkdep_iva2 = 0;
*prcm_pwstctrl_iva2 &= ~0x3;
// Setup MPU domain (enable)
*prcm_clkstctrl_mpu = 0x3;
// Setup CORE domain (enable)
*prcm_clkstctrl_core = 0xf; // Autosleep L3&L4
// Setup PER domain (enable)
*prcm_sleepdep_per |= (1<<1); // Enable PER-MPU sleep dep.
*prcm_clkstctrl_per |= 0x3; // Enable autosleep
// Setup DSS domain (unused, disable)
*prcm_fclken_dss = 0;
*prcm_iclken_dss = 0;
*prcm_clkstctrl_dss = 0x3;
*prcm_wkdep_dss = 0;
*prcm_pwstctrl_dss &= ~0x3;
// Setup CAM comain (unused, disable)
*prcm_clkstctrl_cam = 0x3;
*prcm_wkdep_cam = 0;
*prcm_pwstctrl_cam &= ~0x3;
// Setup NEON domain
*prcm_clkstctrl_neon = 0x3;
// Setup USBHOST domain (unused, disable)
*prcm_clkstctrl_usbhost = 0x3;
*prcm_wkdep_usbhost = 0;
*prcm_pwstctrl_usbhost &= ~0x3;
}
void omap35x_prcm_enable() {
// Prepare GPTIMER2
*prcm_fclken_per |= (1<<3); // Enable GPT2 fclk
*prcm_iclken_per |= (1<<3); // Enable GPT2 iclk
*prcm_autoidle_per |= (1<<3); // Enable GPT2 iclk autoidle
*prcm_clksel_per &= ~(1<<0); // GPT2 fclk = 32.768kHz
*prcm_mpugrpsel_per |= (1<<3); // GPT2 wakes up MPU
*prcm_wken_per |= (1<<3); // GPT2 wake up enable
// Prepare UART3
*prcm_autoidle_per |= (1<<11); // Enable UART3 iclk autoidle
*prcm_mpugrpsel_per |= (1<<11); // UART3 wakes up MPU
*prcm_wken_per |= (1<<11); // UART3 wake up enable
}

260
omap35x_prcm.cc Normal file
View File

@@ -0,0 +1,260 @@
#include <stdint.h>
#include <stdio.h>
#include "omap35x_prcm.hh"
#include "util.hh"
class OMAP35x_prcm_impl {
public:
OMAP35x_prcm_impl(uintptr_t cm_base, uintptr_t pm_base) :cm_base_(cm_base), pm_base_(pm_base) {
// Setup IVA2 domain (unused, disable)
r_clkstctrl_iva2() = 0x3;
r_wkdep_iva2() = 0;
r_pwstctrl_iva2() &= ~0x3;
// Setup MPU domain (enable)
r_clkstctrl_mpu() = 0x3;
// Setup CORE domain (enable)
r_clkstctrl_core() = 0xf; // Autosleep L3&L4
// Setup PER domain (enable)
r_sleepdep_per() |= (1<<1); // Enable PER-MPU sleep dep.
r_clkstctrl_per() |= 0x3; // Enable autosleep
// Setup SGX domain (unused, disable)
r_clkstctrl_sgx() = 0x3;
r_wkdep_sgx() = 0;
r_pwstctrl_sgx() &= ~0x3;
// Setup DSS domain (unused, disable)
r_fclken_dss() = 0;
r_iclken_dss() = 0;
r_clkstctrl_dss() = 0x3;
r_wkdep_dss() = 0;
r_pwstctrl_dss() &= ~0x3;
// Setup CAM comain (unused, disable)
r_clkstctrl_cam() = 0x3;
r_wkdep_cam() = 0;
r_pwstctrl_cam() &= ~0x3;
// Setup NEON domain
r_clkstctrl_neon() = 0x3;
// Setup USBHOST domain (unused, disable)
r_clkstctrl_usbhost() = 0x3;
r_wkdep_usbhost() = 0;
r_pwstctrl_usbhost() &= ~0x3;
}
void enable_peripherals() {
// Prepare GPTIMER2
r_fclken_per() |= (1<<3); // Enable GPT2 fclk
r_iclken_per() |= (1<<3); // Enable GPT2 iclk
r_autoidle_per() |= (1<<3); // Enable GPT2 iclk autoidle
r_clksel_per() &= ~(1<<0); // GPT2 fclk = 32.768kHz
r_mpugrpsel_per() |= (1<<3); // GPT2 wakes up MPU
r_wken_per() |= (1<<3); // GPT2 wake up enable
// Prepare UART3
r_autoidle_per() |= (1<<11); // Enable UART3 iclk autoidle
r_mpugrpsel_per() |= (1<<11); // UART3 wakes up MPU
r_wken_per() |= (1<<11); // UART3 wake up enable
}
private:
uintptr_t cm_base_, pm_base_;
// CM registers
uint32_t volatile& r_fclken_iva2() { return _reg32(cm_base_, 0x0); }
uint32_t volatile& r_clken_pll_iva2() { return _reg32(cm_base_, 0x4); }
uint32_t volatile& r_idlest_iva2() { return _reg32(cm_base_, 0x20); }
uint32_t volatile& r_idlest_pll_iva2() { return _reg32(cm_base_, 0x24); }
uint32_t volatile& r_autoidle_pll_iva2() { return _reg32(cm_base_, 0x34); }
uint32_t volatile& r_clksel1_pll_iva2() { return _reg32(cm_base_, 0x40); }
uint32_t volatile& r_clksel2_pll_iva2() { return _reg32(cm_base_, 0x44); }
uint32_t volatile& r_clkstctrl_iva2() { return _reg32(cm_base_, 0x48); }
uint32_t volatile& r_clkstst_iva2() { return _reg32(cm_base_, 0x4c); }
uint32_t volatile& r_clken_pll_mpu() { return _reg32(cm_base_, 0x904); }
uint32_t volatile& r_idlest_mpu() { return _reg32(cm_base_, 0x920); }
uint32_t volatile& r_idlest_pll_mpu() { return _reg32(cm_base_, 0x924); }
uint32_t volatile& r_autoidle_pll_mpu() { return _reg32(cm_base_, 0x934); }
uint32_t volatile& r_clksel1_pll_mpu() { return _reg32(cm_base_, 0x940); }
uint32_t volatile& r_clksel2_pll_mpu() { return _reg32(cm_base_, 0x944); }
uint32_t volatile& r_clkstctrl_mpu() { return _reg32(cm_base_, 0x948); }
uint32_t volatile& r_clkstst_mpu() { return _reg32(cm_base_, 0x94c); }
uint32_t volatile& r_fclken1_core() { return _reg32(cm_base_, 0xa00); }
uint32_t volatile& r_fclken3_core() { return _reg32(cm_base_, 0xa08); }
uint32_t volatile& r_iclken1_core() { return _reg32(cm_base_, 0xa10); }
uint32_t volatile& r_iclken3_core() { return _reg32(cm_base_, 0xa18); }
uint32_t volatile& r_idlest1_core() { return _reg32(cm_base_, 0xa20); }
uint32_t volatile& r_idlest3_core() { return _reg32(cm_base_, 0xa28); }
uint32_t volatile& r_autoidle1_core() { return _reg32(cm_base_, 0xa30); }
uint32_t volatile& r_autoidle3_core() { return _reg32(cm_base_, 0xa38); }
uint32_t volatile& r_clksel_core() { return _reg32(cm_base_, 0xa40); }
uint32_t volatile& r_clkstctrl_core() { return _reg32(cm_base_, 0xa48); }
uint32_t volatile& r_clkstst_core() { return _reg32(cm_base_, 0xa4c); }
uint32_t volatile& r_fclken_sgx() { return _reg32(cm_base_, 0xb00); }
uint32_t volatile& r_iclken_sgx() { return _reg32(cm_base_, 0xb10); }
uint32_t volatile& r_idlest_sgx() { return _reg32(cm_base_, 0xb20); }
uint32_t volatile& r_clksel_sgx() { return _reg32(cm_base_, 0xb40); }
uint32_t volatile& r_sleepdep_sgx() { return _reg32(cm_base_, 0xb44); }
uint32_t volatile& r_clkstctrl_sgx() { return _reg32(cm_base_, 0xb48); }
uint32_t volatile& r_clkstst_sgx() { return _reg32(cm_base_, 0xb4c); }
uint32_t volatile& r_fclken_wkup() { return _reg32(cm_base_, 0xc00); }
uint32_t volatile& r_iclken_wkup() { return _reg32(cm_base_, 0xc10); }
uint32_t volatile& r_idlest_wkup() { return _reg32(cm_base_, 0xc20); }
uint32_t volatile& r_autoidle_wkup() { return _reg32(cm_base_, 0xc30); }
uint32_t volatile& r_clksel_wkup() { return _reg32(cm_base_, 0xc40); }
uint32_t volatile& r_clken1_pll() { return _reg32(cm_base_, 0xd00); }
uint32_t volatile& r_clken2_pll() { return _reg32(cm_base_, 0xd04); }
uint32_t volatile& r_idlest1_pll() { return _reg32(cm_base_, 0xd20); }
uint32_t volatile& r_idlest2_pll() { return _reg32(cm_base_, 0xd24); }
uint32_t volatile& r_autoidle_pll() { return _reg32(cm_base_, 0xd30); }
uint32_t volatile& r_autoidle2_pll() { return _reg32(cm_base_, 0xd34); }
uint32_t volatile& r_clksel1_pll() { return _reg32(cm_base_, 0xd40); }
uint32_t volatile& r_clksel2_pll() { return _reg32(cm_base_, 0xd44); }
uint32_t volatile& r_clksel3_pll() { return _reg32(cm_base_, 0xd48); }
uint32_t volatile& r_clksel4_pll() { return _reg32(cm_base_, 0xd4c); }
uint32_t volatile& r_clksel5_pll() { return _reg32(cm_base_, 0xd50); }
uint32_t volatile& r_clkout_ctrl() { return _reg32(cm_base_, 0xd70); }
uint32_t volatile& r_fclken_dss() { return _reg32(cm_base_, 0xe00); }
uint32_t volatile& r_iclken_dss() { return _reg32(cm_base_, 0xe10); }
uint32_t volatile& r_idlest_dss() { return _reg32(cm_base_, 0xe20); }
uint32_t volatile& r_autoidle_dss() { return _reg32(cm_base_, 0xe30); }
uint32_t volatile& r_clksel_dss() { return _reg32(cm_base_, 0xe40); }
uint32_t volatile& r_sleepdep_dss() { return _reg32(cm_base_, 0xe44); }
uint32_t volatile& r_clkstctrl_dss() { return _reg32(cm_base_, 0xe48); }
uint32_t volatile& r_clkstst_dss() { return _reg32(cm_base_, 0xe4c); }
uint32_t volatile& r_fclken_cam() { return _reg32(cm_base_, 0xf00); }
uint32_t volatile& r_iclken_cam() { return _reg32(cm_base_, 0xf10); }
uint32_t volatile& r_idlest_cam() { return _reg32(cm_base_, 0xf20); }
uint32_t volatile& r_autoidle_cam() { return _reg32(cm_base_, 0xf30); }
uint32_t volatile& r_clksel_cam() { return _reg32(cm_base_, 0xf40); }
uint32_t volatile& r_sleepdep_cam() { return _reg32(cm_base_, 0xf44); }
uint32_t volatile& r_clkstctrl_cam() { return _reg32(cm_base_, 0xf48); }
uint32_t volatile& r_clkstst_cam() { return _reg32(cm_base_, 0xf4c); }
uint32_t volatile& r_fclken_per() { return _reg32(cm_base_, 0x1000); }
uint32_t volatile& r_iclken_per() { return _reg32(cm_base_, 0x1010); }
uint32_t volatile& r_idlest_per() { return _reg32(cm_base_, 0x1020); }
uint32_t volatile& r_autoidle_per() { return _reg32(cm_base_, 0x1030); }
uint32_t volatile& r_clksel_per() { return _reg32(cm_base_, 0x1040); }
uint32_t volatile& r_sleepdep_per() { return _reg32(cm_base_, 0x1044); }
uint32_t volatile& r_clkstctrl_per() { return _reg32(cm_base_, 0x1048); }
uint32_t volatile& r_clkstst_per() { return _reg32(cm_base_, 0x104c); }
uint32_t volatile& r_idlest_neon() { return _reg32(cm_base_, 0x1320); }
uint32_t volatile& r_clkstctrl_neon() { return _reg32(cm_base_, 0x1348); }
uint32_t volatile& r_fclken_usbhost() { return _reg32(cm_base_, 0x1400); }
uint32_t volatile& r_iclken_usbhost() { return _reg32(cm_base_, 0x1410); }
uint32_t volatile& r_idlest_usbhost() { return _reg32(cm_base_, 0x1420); }
uint32_t volatile& r_autoidle_usbhost() { return _reg32(cm_base_, 0x1430); }
uint32_t volatile& r_clksel_usbhost() { return _reg32(cm_base_, 0x1440); }
uint32_t volatile& r_sleepdep_usbhost() { return _reg32(cm_base_, 0x1444); }
uint32_t volatile& r_clkstctrl_usbhost() { return _reg32(cm_base_, 0x1448); }
uint32_t volatile& r_clkstst_usbhost() { return _reg32(cm_base_, 0x144c); }
// PM registers
uint32_t volatile& r_rstctrl_iva2() {return _reg32(pm_base_, 0x50); }
uint32_t volatile& r_rstst_iva2() {return _reg32(pm_base_, 0x58); }
uint32_t volatile& r_wkdep_iva2() {return _reg32(pm_base_, 0xc8); }
uint32_t volatile& r_pwstctrl_iva2() {return _reg32(pm_base_, 0xe0); }
uint32_t volatile& r_pwstst_iva2() {return _reg32(pm_base_, 0xe4); }
uint32_t volatile& r_prepwstst_iva2() {return _reg32(pm_base_, 0xe8); }
uint32_t volatile& r_irqstatus_iva2() {return _reg32(pm_base_, 0xf8); }
uint32_t volatile& r_irqenable_iva2() {return _reg32(pm_base_, 0xfc); }
uint32_t volatile& r_rstst_mpu() {return _reg32(pm_base_, 0x958); }
uint32_t volatile& r_wkdep_mpu() {return _reg32(pm_base_, 0x9c8); }
uint32_t volatile& r_evgenctrl_mpu() {return _reg32(pm_base_, 0x9d4); }
uint32_t volatile& r_evgenontim_mpu() {return _reg32(pm_base_, 0x9d8); }
uint32_t volatile& r_evgenofftim_mpu() {return _reg32(pm_base_, 0x9dc); }
uint32_t volatile& r_pwstctrl_mpu() {return _reg32(pm_base_, 0x9e0); }
uint32_t volatile& r_pwstst_mpu() {return _reg32(pm_base_, 0x9e4); }
uint32_t volatile& r_prepwstst_mpu() {return _reg32(pm_base_, 0x9e8); }
uint32_t volatile& r_rstst_core() {return _reg32(pm_base_, 0xa58); }
uint32_t volatile& r_wken1_core() {return _reg32(pm_base_, 0xaa0); }
uint32_t volatile& r_mpugrpsel1_core() {return _reg32(pm_base_, 0xaa4); }
uint32_t volatile& r_iva2grpsel1_core() {return _reg32(pm_base_, 0xaa8); }
uint32_t volatile& r_wkst1_core() {return _reg32(pm_base_, 0xab0); }
uint32_t volatile& r_wkst3_core() {return _reg32(pm_base_, 0xab8); }
uint32_t volatile& r_pwstctrl_core() {return _reg32(pm_base_, 0xae0); }
uint32_t volatile& r_pwstst_core() {return _reg32(pm_base_, 0xae4); }
uint32_t volatile& r_prepwstst_core() {return _reg32(pm_base_, 0xae8); }
uint32_t volatile& r_wken3_core() {return _reg32(pm_base_, 0xaf0); }
uint32_t volatile& r_iva2grpsel2_core() {return _reg32(pm_base_, 0xaf4); }
uint32_t volatile& r_mpugrpsel2_core() {return _reg32(pm_base_, 0xaf8); }
uint32_t volatile& r_rstst_sgx() {return _reg32(pm_base_, 0xb58); }
uint32_t volatile& r_wkdep_sgx() {return _reg32(pm_base_, 0xbc8); }
uint32_t volatile& r_pwstctrl_sgx() {return _reg32(pm_base_, 0xbe0); }
uint32_t volatile& r_pwstst_sgx() {return _reg32(pm_base_, 0xbe4); }
uint32_t volatile& r_prepwstst_sgx() {return _reg32(pm_base_, 0xbe8); }
uint32_t volatile& r_wken_wkup() {return _reg32(pm_base_, 0xca0); }
uint32_t volatile& r_mpugrpsel_wkup() {return _reg32(pm_base_, 0xca4); }
uint32_t volatile& r_iva2grpsel_wkup() {return _reg32(pm_base_, 0xca8); }
uint32_t volatile& r_wkst_wkup() {return _reg32(pm_base_, 0xcb0); }
uint32_t volatile& r_rstst_dss() {return _reg32(pm_base_, 0xe58); }
uint32_t volatile& r_wken_dss() {return _reg32(pm_base_, 0xec8); }
uint32_t volatile& r_wkdep_dss() {return _reg32(pm_base_, 0xec8); }
uint32_t volatile& r_pwstctrl_dss() {return _reg32(pm_base_, 0xee0); }
uint32_t volatile& r_pwstst_dss() {return _reg32(pm_base_, 0xee4); }
uint32_t volatile& r_prepwstst_dss() {return _reg32(pm_base_, 0xee8); }
uint32_t volatile& r_rstst_cam() {return _reg32(pm_base_, 0xf58); }
uint32_t volatile& r_wkdep_cam() {return _reg32(pm_base_, 0xfc8); }
uint32_t volatile& r_pwstctrl_cam() {return _reg32(pm_base_, 0xfe0); }
uint32_t volatile& r_pwstst_cam() {return _reg32(pm_base_, 0xfe4); }
uint32_t volatile& r_prepwstst_cam() {return _reg32(pm_base_, 0xfe8); }
uint32_t volatile& r_rstst_per() {return _reg32(pm_base_, 0x1058); }
uint32_t volatile& r_wken_per() {return _reg32(pm_base_, 0x10a0); }
uint32_t volatile& r_mpugrpsel_per() {return _reg32(pm_base_, 0x10a4); }
uint32_t volatile& r_iva2grpsel_per() {return _reg32(pm_base_, 0x10a8); }
uint32_t volatile& r_wkst_per() {return _reg32(pm_base_, 0x10b0); }
uint32_t volatile& r_wkdep_per() {return _reg32(pm_base_, 0x10c8); }
uint32_t volatile& r_pwstctrl_per() {return _reg32(pm_base_, 0x10e0); }
uint32_t volatile& r_pwstst_per() {return _reg32(pm_base_, 0x10e4); }
uint32_t volatile& r_prepwstst_per() {return _reg32(pm_base_, 0x10e8); }
uint32_t volatile& r_rstst_neon() {return _reg32(pm_base_, 0x1358); }
uint32_t volatile& r_wkdep_neon() {return _reg32(pm_base_, 0x13c8); }
uint32_t volatile& r_pwstctrl_neon() {return _reg32(pm_base_, 0x13e0); }
uint32_t volatile& r_pwstst_neon() {return _reg32(pm_base_, 0x13e4); }
uint32_t volatile& r_prepwstst_neon() {return _reg32(pm_base_, 0x13e8); }
uint32_t volatile& r_rstst_usbhost() {return _reg32(pm_base_, 0x1458); }
uint32_t volatile& r_wken_usbhost() {return _reg32(pm_base_, 0x14a0); }
uint32_t volatile& r_mpugrpsel_usbhost() {return _reg32(pm_base_, 0x14a4); }
uint32_t volatile& r_iva2grpsel_usbhost() {return _reg32(pm_base_, 0x14a8); }
uint32_t volatile& r_wkst_usbhost() {return _reg32(pm_base_, 0x14b0); }
uint32_t volatile& r_wkdep_usbhost() {return _reg32(pm_base_, 0x14c8); }
uint32_t volatile& r_pwstctrl_usbhost() {return _reg32(pm_base_, 0x14e0); }
uint32_t volatile& r_pwstst_usbhost() {return _reg32(pm_base_, 0x14e4); }
uint32_t volatile& r_prepwstst_usbhost() {return _reg32(pm_base_, 0x14e8); }
};
OMAP35x_prcm::OMAP35x_prcm(uintptr_t cm_base, uintptr_t pm_base) : impl_(new OMAP35x_prcm_impl(cm_base, pm_base)) {
}
OMAP35x_prcm::~OMAP35x_prcm() {
}
void OMAP35x_prcm::enable_peripherals() {
impl_->enable_peripherals();
}

View File

@@ -1,10 +0,0 @@
#ifndef _OMAP35X_PRCM_H_
#define _OMAP35x_PRCM_H_
// Initialize the power&clock manager
void omap35x_prcm_init();
// Enable clock&power for all used peripherals
void omap35x_prcm_enable();
#endif

20
omap35x_prcm.hh Normal file
View File

@@ -0,0 +1,20 @@
#ifndef _OMAP35X_PRCM_HH_
#define _OMAP35x_PRCM_HH_
#include <memory>
class OMAP35x_prcm_impl;
class OMAP35x_prcm {
public:
OMAP35x_prcm(uintptr_t cm_base, uintptr_t pm_base);
~OMAP35x_prcm();
// Enable clock&power for all used peripherals
void enable_peripherals();
private:
std::unique_ptr<OMAP35x_prcm_impl> impl_;
};
#endif

View File

@@ -5,7 +5,17 @@
#undef errno
extern int errno;
#include "uart.h"
#include "uart.hh"
static ICharacterDevice* console = nullptr;
void setConsole(ICharacterDevice* newConsole) {
console = newConsole;
}
#ifdef __cplusplus
extern "C" {
#endif
int _close(int file) __attribute__((used));
int _close(int file) {
@@ -33,16 +43,26 @@ int _read(int file, char *ptr, int len) {
/* if(file != 0) */
/* return 0; */
return uart_read(ptr, len);
if(console)
return console->read(ptr, len);
else {
errno = EIO;
return -1;
}
}
int _write(int file, char *ptr, int len) __attribute__((used));
int _write(int file, char *ptr, int len) {
int _write(int file, const char *ptr, int len) __attribute__((used));
int _write(int file, const char *ptr, int len) {
// if(file != 1 && file != 2) // Only stdout supported
//return 0;
uart_write(ptr, len);
return len;
if(console) {
console->write(ptr, len);
return len;
} else {
errno = EIO;
return -1;
}
}
extern char __heap_end, __heap_start;
@@ -73,3 +93,12 @@ int _getpid(void) __attribute__((used));
int _getpid(void) {
return 1;
}
int _open(const char *name, int flags, int mode) __attribute__((used));
int _open(const char *name, int flags, int mode) {
return -1;
}
#ifdef __cplusplus
}
#endif

BIN
u-boot.bin Executable file

Binary file not shown.

141
uart.c
View File

@@ -1,141 +0,0 @@
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "cortexa8.h"
#include "omap35x_intc.h"
#include "uart.h"
static volatile uint8_t *const uart_data = (uint8_t*)0x49020000;
static volatile uint8_t *const uart_dll = (uint8_t*)0x49020000;
static volatile uint8_t *const uart_dlh = (uint8_t*)0x49020004;
static volatile uint8_t *const uart_ier = (uint8_t*)0x49020004;
static volatile uint8_t *const uart_fcr = (uint8_t*)0x49020008;
static volatile uint8_t *const uart_efr = (uint8_t*)0x49020008;
static volatile uint8_t *const uart_lcr = (uint8_t*)0x4902000c;
static volatile uint8_t *const uart_lsr = (uint8_t*)0x49020014;
static volatile uint8_t *const uart_ssr = (uint8_t*)0x49020044;
static volatile uint8_t *const uart_sysc = (uint8_t*)0x49020054;
static volatile uint8_t *const uart_wer = (uint8_t*)0x4902005C;
static volatile uint32_t *const prcm_wkst_per = (uint32_t*)0x483070b0;
#define RECVBUFFERSIZE 128
static volatile char recvbuffer[RECVBUFFERSIZE];
static volatile int recvbuffer_rdptr = (RECVBUFFERSIZE-1), recvbuffer_wrptr = 0;
static volatile bool newdata = false;
static bool echo = true;
static void _uart_wait_txnotfull() {
while(*uart_ssr & 0x1) {}
}
static void _uart_wait_rxnotempty() {
while(!(*uart_lsr & 0x1)) {}
}
void uart_sendb(char b) {
_uart_wait_txnotfull();
*uart_data = b;
}
char uart_recvb() {
_uart_wait_rxnotempty();
return *uart_data;
}
void uart_write(const char *data, int len) {
for(int i = 0;i < len;++i)
uart_sendb(*data++);
}
int uart_read(char *buf, int len) {
int pos = 0;
while(true) {
bool oldint = cortexa8_get_int();
cortexa8_dis_int();
// Data available in recvbuffer?
if(((recvbuffer_rdptr+1)%RECVBUFFERSIZE) != recvbuffer_wrptr) {
int avail = recvbuffer_wrptr - recvbuffer_rdptr;
if(avail < 0)
avail = RECVBUFFERSIZE+avail;
avail -= 1;
// Advance to first byte to read
recvbuffer_rdptr = (recvbuffer_rdptr+1)%RECVBUFFERSIZE;
int toread = (avail>len)?len:avail;
if(toread+recvbuffer_rdptr > RECVBUFFERSIZE) {
memcpy(buf+pos, (char*)recvbuffer+recvbuffer_rdptr, RECVBUFFERSIZE-(recvbuffer_rdptr));
toread -= RECVBUFFERSIZE-recvbuffer_rdptr;
pos += RECVBUFFERSIZE-recvbuffer_rdptr;
recvbuffer_rdptr = 0;
}
memcpy(buf+pos, (char*)recvbuffer+recvbuffer_rdptr, toread);
pos += toread;
recvbuffer_rdptr = (recvbuffer_rdptr+toread-1)%RECVBUFFERSIZE;
}
newdata = false;
// Try to read directly from UART if more data req'd than was in buffer
while((pos < len) && (*uart_lsr & 0x1)) {
char rd = *uart_data;
if(rd == '\r')
rd = '\n';
if(echo)
uart_sendb(rd);
buf[pos++] = rd;
}
if(oldint)
cortexa8_ena_int();
if(pos > 0)
return pos;
while(!newdata)
__asm__ __volatile__ ("wfi"); // If we didn't get any data, wait
}
}
void uart_recv_handler(void *unused) {
while(*uart_lsr & 0x1) { // while there are bytes
char rd = *uart_data;
if(rd == '\r')
rd = '\n';
if(echo)
uart_sendb(rd);
if(recvbuffer_wrptr == recvbuffer_rdptr) { // Overflow
} else {
recvbuffer[recvbuffer_wrptr] = rd;
recvbuffer_wrptr = (recvbuffer_wrptr+1)%RECVBUFFERSIZE;
}
}
newdata = true;
*prcm_wkst_per = (1<<11); // Clear UART3 wake bit
}
void uart_init() {
omap35x_intc_register(74, &uart_recv_handler, NULL, 1);
omap35x_intc_ena(74);
*uart_lcr = 0xBF; // Configuration mode B
uint8_t dllsave = *uart_dll, dlhsave = *uart_dlh;
*uart_dll = 0;
*uart_dlh = 0;
*uart_efr |= (1<<4);
*uart_lcr = 0x80; // Configuration mode A
*uart_fcr = 0x21;
*uart_sysc = 0x15;
*uart_wer |= (1<<5);
*uart_dll = dllsave;
*uart_dlh = dlhsave;
*uart_lcr = 0x03; // Operational mode
*uart_ier = 0x11;
}

199
uart.cc Normal file
View File

@@ -0,0 +1,199 @@
#include <cstdint>
#include <cstring>
#include <array>
#include "cortexa8.hh"
#include "omap35x_intc.hh"
#include "uart.hh"
#include "util.hh"
class UART_impl {
public:
UART_impl(uintptr_t base, int irq) : base_(base), irq_(irq) {
OMAP35x_intc::get().register_handler(irq_, std::bind(&UART_impl::recv_handler, this), 1);
OMAP35x_intc::get().enable_int(irq_);
r_lcr() = 0xBF; // Configuration mode B
uint8_t dllsave = r_dll(), dlhsave = r_dlh();
r_dll() = 0;
r_dlh() = 0;
r_efr() |= (1<<4);
r_lcr() = 0x80; // Configuration mode A
r_fcr() = 0x21;
r_sysc() = 0x15;
r_wer() |= (1<<5);
r_dll() = dllsave;
r_dlh() = dlhsave;
r_lcr() = 0x03; // Operational mode
r_ier() = 0x11;
}
~UART_impl() {
OMAP35x_intc::get().disable_int(irq_);
}
void write(char const* data, int const& len) {
for(int i = 0;i < len;++i)
sendb(*data++);
}
int read(char *buf, int const& len) {
int pos = 0;
while(true) {
bool oldint = cortexa8_get_int();
cortexa8_dis_int();
// Data available in recvbuffer?
if(((recvbuffer_rdptr_+1)%RECVBUFFERSIZE) != recvbuffer_wrptr_) {
int avail = recvbuffer_wrptr_ - recvbuffer_rdptr_;
if(avail < 0)
avail = RECVBUFFERSIZE+avail;
avail -= 1;
// Advance to first byte to read
recvbuffer_rdptr_ = (recvbuffer_rdptr_+1)%RECVBUFFERSIZE;
int toread = (avail>len)?len:avail;
if(toread+recvbuffer_rdptr_ > RECVBUFFERSIZE) {
memcpy(buf+pos, &recvbuffer_[recvbuffer_rdptr_], RECVBUFFERSIZE-(recvbuffer_rdptr_));
toread -= RECVBUFFERSIZE-recvbuffer_rdptr_;
pos += RECVBUFFERSIZE-recvbuffer_rdptr_;
recvbuffer_rdptr_ = 0;
}
memcpy(buf+pos, &recvbuffer_[recvbuffer_rdptr_], toread);
pos += toread;
recvbuffer_rdptr_ = (recvbuffer_rdptr_+toread-1)%RECVBUFFERSIZE;
}
newdata_ = false;
// Try to read directly from UART if more data req'd than was in buffer
while((pos < len) && (r_lsr() & 0x1)) {
char rd = r_data();
if(rd == '\r')
rd = '\n';
if(echo_)
sendb(rd);
buf[pos++] = rd;
}
if(oldint)
cortexa8_ena_int();
if(pos > 0)
return pos;
while(!newdata_)
__asm__ __volatile__ ("wfi"); // If we didn't get any data, wait
}
}
private:
void recv_handler() {
while(r_lsr() & 0x1) { // while there are bytes
char rd = r_data();
if(rd == '\r')
rd = '\n';
if(echo_)
sendb(rd);
if(recvbuffer_wrptr_ == recvbuffer_rdptr_) { // Overflow
} else {
recvbuffer_[recvbuffer_wrptr_] = rd;
recvbuffer_wrptr_ = (recvbuffer_wrptr_+1)%RECVBUFFERSIZE;
}
}
newdata_ = true;
*prcm_wkst_per = (1<<11); // Clear UART3 wake bit
}
uintptr_t base_;
int irq_;
uint8_t volatile& r_data() {
return _reg8(base_, 0);
}
uint8_t volatile& r_dll() {
return _reg8(base_, 0);
}
uint8_t volatile& r_dlh() {
return _reg8(base_, 4);
}
uint8_t volatile& r_ier() {
return _reg8(base_, 4);
}
uint8_t volatile& r_fcr() {
return _reg8(base_, 8);
}
uint8_t volatile& r_efr() {
return _reg8(base_, 8);
}
uint8_t volatile& r_lcr() {
return _reg8(base_, 0xc);
}
uint8_t volatile& r_lsr() {
return _reg8(base_, 0x14);
}
uint8_t volatile& r_ssr() {
return _reg8(base_, 0x44);
}
uint8_t volatile& r_sysc() {
return _reg8(base_, 0x54);
}
uint8_t volatile& r_wer() {
return _reg8(base_, 0x5c);
}
volatile uint32_t *const prcm_wkst_per = (uint32_t*)0x483070b0;
static const size_t RECVBUFFERSIZE = 128;
std::array<char, RECVBUFFERSIZE> recvbuffer_;
volatile size_t recvbuffer_rdptr_ = (RECVBUFFERSIZE-1), recvbuffer_wrptr_ = 0;
volatile bool newdata_ = false;
bool echo_ = true;
void _wait_txnotfull() {
while(r_ssr() & 0x1) {}
}
void _wait_rxnotempty() {
while(!(r_lsr() & 0x1)) {}
}
void sendb(char b) {
_wait_txnotfull();
r_data() = b;
}
char recvb() {
_wait_rxnotempty();
return r_data();
}
};
UART::UART(uintptr_t base, int irq) : impl_(new UART_impl(base, irq)) {
}
UART::~UART() {
}
void UART::write(const char *data, int const& len) {
impl_->write(data, len);
}
int UART::read(char *buf, int const& len) {
return impl_->read(buf, len);
}

11
uart.h
View File

@@ -1,11 +0,0 @@
#ifndef _UART_H_
#define _UART_H_
void uart_init();
//void uart_sendb(char b);
//char uart_recvb();
void uart_write(const char *data, int len);
int uart_read(char *buf, int len);
#endif

28
uart.hh Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _UART_HH_
#define _UART_HH_
#include <cstdint>
#include <memory>
class ICharacterDevice {
public:
virtual void write(char const* data, int const& len) = 0;
virtual int read(char *buf, int const& len) = 0;
};
class UART_impl;
class UART : public ICharacterDevice {
public:
UART(uintptr_t base, int irq);
~UART();
virtual void write(char const* data, int const& len);
virtual int read(char *buf, int const& len);
private:
std::unique_ptr<UART_impl> impl_;
};
#endif

25
util.hh Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _UTIL_HH_
#define _UTIL_HH_
#include <cstdint>
// Functions to access hardware registers. GCC will generate memory access instructions of the correct width.
// Usage: "_reg8(base, ofs) = 0xf0;" to set
// "uint8_t foo = _reg8(base, ofs);" to get
// Read/modify/write like "_reg8(base, ofs) |= (1<<7);" also works as expected.
constexpr inline uint8_t volatile& _reg8(uintptr_t const& base, size_t const& ofs) noexcept __attribute__((const));
constexpr inline uint8_t volatile& _reg8(uintptr_t const& base, size_t const& ofs) noexcept {
return *reinterpret_cast<uint8_t*>(base+ofs);
}
constexpr inline uint16_t volatile& _reg16(uintptr_t const& base, size_t const& ofs) noexcept __attribute__((const));
constexpr inline uint16_t volatile& _reg16(uintptr_t const& base, size_t const& ofs) noexcept {
return *reinterpret_cast<uint16_t*>(base+ofs);
}
constexpr inline uint32_t volatile& _reg32(uintptr_t const& base, size_t const& ofs) noexcept __attribute__((const));
constexpr inline uint32_t volatile& _reg32(uintptr_t const& base, size_t const& ofs) noexcept {
return *reinterpret_cast<uint32_t*>(base+ofs);
}
#endif

BIN
x-load.bin.ift Executable file

Binary file not shown.