- Now using C++
- Added missing boot image files for x-load and u-boot
This commit is contained in:
27
Makefile
27
Makefile
@@ -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))
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
37
cortexa8.h
37
cortexa8.h
@@ -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
44
cortexa8.hh
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
90
drv_omap35x_gpt.cc
Normal 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);
|
||||
}
|
||||
@@ -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
25
drv_omap35x_gpt.hh
Normal 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
208
fw_cxx.ld
Normal 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_*) }
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef _OMAP35X_H_
|
||||
#define _OMAP35X_H_
|
||||
|
||||
void omap35x_print_chip_id();
|
||||
|
||||
#endif
|
||||
6
omap35x.hh
Normal file
6
omap35x.hh
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _OMAP35X_HH_
|
||||
#define _OMAP35X_HH_
|
||||
|
||||
void omap35x_print_chip_id();
|
||||
|
||||
#endif
|
||||
@@ -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
130
omap35x_intc.cc
Normal 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_;
|
||||
}
|
||||
@@ -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
28
omap35x_intc.hh
Normal 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
|
||||
@@ -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
260
omap35x_prcm.cc
Normal 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();
|
||||
}
|
||||
@@ -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
20
omap35x_prcm.hh
Normal 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
|
||||
41
syscall.c
41
syscall.c
@@ -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
BIN
u-boot.bin
Executable file
Binary file not shown.
141
uart.c
141
uart.c
@@ -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
199
uart.cc
Normal 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
11
uart.h
@@ -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
28
uart.hh
Normal 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
25
util.hh
Normal 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
BIN
x-load.bin.ift
Executable file
Binary file not shown.
Reference in New Issue
Block a user