-Added support for I2C module

-Initial support for TPS65950
-Support for changing CPU frequency in prcm driver
-Preparations for context switching
This commit is contained in:
2013-07-12 20:29:34 +02:00
parent cf621c5fed
commit ba680cccdf
18 changed files with 527 additions and 22 deletions

View File

@@ -5,10 +5,10 @@ OBJCOPY=arm-none-eabi-objcopy
OBJDUMP=arm-none-eabi-objdump
#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 -fno-rtti -fstrict-enums -Wabi -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 -fno-rtti -fstrict-enums -Wabi -Og -flto -D__DYNAMIC_REENT__
LDFLAGS=-static
C_SRCS=syscall.c
CXX_SRCS=cortexa8.cc drv_omap35x_gpt.cc main.cc mm.cc omap35x.cc omap35x_intc.cc omap35x_prcm.cc phys_mm.cc uart.cc
CXX_SRCS=cortexa8.cc drv_omap35x_gpt.cc drv_omap35x_i2c.cc drv_tps65950.cc main.cc mm.cc omap35x.cc omap35x_intc.cc omap35x_prcm.cc phys_mm.cc uart.cc
S_SRCS=cortexa8_asm.s syscall_asm.s
OBJS=$(addprefix objs/,$(C_SRCS:.c=.o)) $(addprefix objs/,$(CXX_SRCS:.cc=.o)) $(addprefix objs/,$(S_SRCS:.s=.o))

View File

@@ -450,3 +450,9 @@ void _cortexa8_syscall() {
void _cortexa8_unhandled_fiq() {
printf("UNHANDLED FINTERRUPT\n");
}
// Context switching stuff
cortexa8::thread_cb initial_thread_cb;
cortexa8::thread_cb *_current_thread_cb = &initial_thread_cb;

View File

@@ -24,6 +24,11 @@ namespace cortexa8 {
void map_pages(uintptr_t virt, uintptr_t phys, unsigned count);
void unmap_pages(uintptr_t virt, unsigned count);
struct thread_cb {
uint32_t regs[15];
uint32_t cpsr;
};
}
// Implemented in cortexa8_asm.s

View File

@@ -110,6 +110,33 @@ cortexa8_get_spsr:
mrs r0, spsr
bx lr
/*
The irq sp (r13) register is loaded with a pointer to the current thread control block.
All registers are saved there, the sp is loaded with __stack_int and the
interrupt handler is called.
The (possibly changed) current thread control block is used to restore context and return.
*/
.global _cortexa8_int
_cortexa8_int:
ldr r13, = _current_thread_cb
ldr r13, [r13]
stm r13, {r0-r14}^
add lr, lr, #-4
str lr, [r13, #60]
mrs r0, spsr
str r0, [r13, #64]
ldr r13, = __stack_int
bl _omap35x_intc_handler
ldr r13, = _current_thread_cb
ldr r13, [r13]
ldr r1, [r13, #64]
msr spsr, r1
ldm r13, {r0-r15}^
.global _vect_table
.align 5
_vect_table:
@@ -126,6 +153,7 @@ _vect_table:
/* Unused */
nop
/* IRQ */
b _omap35x_intc_handler
b _cortexa8_int
/* FIQ */
b _cortexa8_unhandled_fiq

213
drv_omap35x_i2c.cc Normal file
View File

@@ -0,0 +1,213 @@
#include <memory>
#include <cstdint>
#include <cstdio>
#include <cassert>
#include "util.hh"
#include "mmio.hh"
#include "exceptions.hh"
#include "drv_omap35x_i2c.hh"
namespace ex {
class i2c_tmp_fail {};
class i2c_nack : public i2c_tmp_fail {};
class i2c_arbitration_lost : public i2c_tmp_fail {};
class i2c_timeout : public timeout {};
class i2c_error : public error {};
}
class OMAP35x_I2C_impl {
public:
OMAP35x_I2C_impl(uintptr_t base) : base_{base}, xtrsh_{1}, rtrsh_{1} {
r_sysc() = 0x011;
r_psc() = 0x7; // Set clock prescaler to /8 (=12MHz internal clock)
r_scll() = 0x9; // Set low pulse width for 400kHz mode (t_low = 1.3_us)
r_sclh() = 0x9; // Set high pulse width for 400kHz mode (t_high = 1.16_us)
r_oa0() = 0x20; // Set own address to 0x20
r_con() = 0x00008400; // Enable module in master mode
}
~OMAP35x_I2C_impl() {
}
void reg_write(uint8_t slaveid, uint8_t reg, uint8_t value) {
transmit(slaveid, {reg, value});
}
uint8_t reg_read(uint8_t slaveid, uint8_t reg) {
auto tmp = transfer2(slaveid, {reg}, 1);
return tmp[0];
}
void reg_write16(uint8_t slaveid, uint8_t reg, uint16_t value) {
transmit(slaveid, {reg, value&0xff, value>>8});
}
uint16_t reg_read16(uint8_t slaveid, uint8_t reg) {
auto tmp = transfer2(slaveid, {reg}, 2);
return tmp[0] | (tmp[1]<<8);
}
private:
// Send the bytes in 'data' to I2C slave 'slaveid'
void transmit(uint8_t slaveid, std::string const& data) {
bool done = false;
while(!done) {
_wait_busfree();
r_sa() = slaveid&0x7f; // Set slave address
r_cnt() = data.size(); // Set transfer length
r_con() = 0x8603; // master transmit, generate start and stop cond.
try {
_send(data);
done = true;
} catch(ex::i2c_tmp_fail& ex) {
printf("Error, restart transfer\n");
}
}
}
// Two-phase transfer:
// Send the bytes in 'data' to I2C slave 'slaveid',
// then receive 'recvcount' bytes
std::string transfer2(uint8_t slaveid, std::string const& data, size_t recvcount) {
while(true) {
_wait_busfree();
r_sa() = slaveid&0x7f; // Set slave address
r_cnt() = data.size(); // Set transfer length
r_con() = 0x8601; // master transmit, generate start cond.
try {
_send(data);
} catch(ex::i2c_tmp_fail& ex) {
continue; // restart transfer
}
r_cnt() = recvcount;
r_con() = 0x8403; // master receive, generate start and stop cond.
std::string res;
try {
_recv(res);
} catch(ex::i2c_arbitration_lost& ex) {
// Should not happen
throw ex::i2c_error{};
} catch(ex::i2c_tmp_fail& ex) {
continue; // restart transfer
}
return res;
}
}
void _send(std::string const& data) {
size_t pos = 0;
while(true) {
auto stat = r_stat();
if(stat & (1<<1)) { // NACK
r_stat() = (1<<1); // clear NACK bit
throw ex::i2c_nack{};
} else if (stat & (1<<0)) { // ARB lost
r_stat() = (1<<0); // clear AL bit
throw ex::i2c_arbitration_lost{};
} else if (stat & (1<<2)) { // ARDY (xfer complete)
r_stat() = (1<<2); // clear ARDY bit
return;
} else if (stat & (1<<14)) { // XDR
unsigned writecnt = r_bufstat() & 0x3f;
assert(writecnt <= data.size()-pos);
for(size_t i = 0;i < writecnt;++i)
r_data() = data[i+pos]&0xff;
pos += writecnt;
r_stat() = (1<<14); // clear XDR bit
} else if (stat & (1<<4)) { // XRDY
assert(xtrsh_ <= data.size()-pos);
for(size_t i = 0;i < xtrsh_;++i)
r_data() = data[i+pos]&0xff;
pos += xtrsh_;
r_stat() = (1<<4); // clear XRDY bit
}
}
}
void _recv(std::string& data) {
while(true) {
auto stat = r_stat();
if(stat & (1<<1)) { // NACK
r_stat() = (1<<1); // clear NACK bit
throw ex::i2c_nack{};
} else if (stat & (1<<0)) { // ARB lost
r_stat() = (1<<0); // clear AL bit
throw ex::i2c_arbitration_lost{};
} else if (stat & (1<<2)) { // ARDY (xfer complete)
r_stat() = (1<<2); // clear ARDY bit
return;
} else if (stat & (1<<13)) { // RDR
unsigned readcnt = (r_bufstat() & 0x3f00)>>8;
for(size_t i = 0;i < readcnt;++i)
data.push_back(r_data()&0xff);
r_stat() = (1<<13); // clear RDR bit
} else if (stat & (1<<3)) { // RRDY
for(size_t i = 0;i < rtrsh_;++i)
data.push_back(r_data()&0xff);
r_stat() = (1<<3); // clear RRDY bit
}
}
}
void _wait_busfree() {
// Wait while bus busy = 1
while(r_stat() & (1<<12)) {}
}
MMIO_alloc base_;
uint8_t xtrsh_, rtrsh_;
uint8_t volatile& r_rev() { return _reg8(base_.get_virt(), 0x0); }
uint16_t volatile& r_ie() { return _reg16(base_.get_virt(), 0x4); }
uint16_t volatile& r_stat() { return _reg16(base_.get_virt(), 0x8); }
uint16_t volatile& r_we() { return _reg16(base_.get_virt(), 0xc); }
uint8_t volatile& r_syss() { return _reg8(base_.get_virt(), 0x10); }
uint16_t volatile& r_buf() { return _reg16(base_.get_virt(), 0x14); }
uint16_t volatile& r_cnt() { return _reg16(base_.get_virt(), 0x18); }
uint8_t volatile& r_data() { return _reg8(base_.get_virt(), 0x1c); }
uint16_t volatile& r_sysc() { return _reg16(base_.get_virt(), 0x20); }
uint16_t volatile& r_con() { return _reg16(base_.get_virt(), 0x24); }
uint16_t volatile& r_oa0() { return _reg16(base_.get_virt(), 0x28); }
uint16_t volatile& r_sa() { return _reg16(base_.get_virt(), 0x2c); }
uint16_t volatile& r_psc() { return _reg16(base_.get_virt(), 0x30); }
uint16_t volatile& r_scll() { return _reg16(base_.get_virt(), 0x34); }
uint16_t volatile& r_sclh() { return _reg16(base_.get_virt(), 0x38); }
uint16_t volatile& r_systest() { return _reg16(base_.get_virt(), 0x3c); }
uint16_t volatile& r_bufstat() { return _reg16(base_.get_virt(), 0x40); }
uint16_t volatile& r_oa1() { return _reg16(base_.get_virt(), 0x44); }
uint16_t volatile& r_oa2() { return _reg16(base_.get_virt(), 0x48); }
uint16_t volatile& r_oa3() { return _reg16(base_.get_virt(), 0x4c); }
uint8_t volatile& r_actoa() { return _reg8(base_.get_virt(), 0x50); }
uint8_t volatile& r_sblock() { return _reg8(base_.get_virt(), 0x54); }
};
OMAP35x_I2C::OMAP35x_I2C(uintptr_t base) : impl_{new OMAP35x_I2C_impl{base}} {
}
OMAP35x_I2C::~OMAP35x_I2C() {
}
void OMAP35x_I2C::reg_write(uint8_t slaveid, uint8_t reg, uint8_t value) {
impl_->reg_write(slaveid, reg, value);
}
uint8_t OMAP35x_I2C::reg_read(uint8_t slaveid, uint8_t reg) {
return impl_->reg_read(slaveid, reg);
}
void OMAP35x_I2C::reg_write16(uint8_t slaveid, uint8_t reg, uint16_t value) {
impl_->reg_write16(slaveid, reg, value);
}
uint16_t OMAP35x_I2C::reg_read16(uint8_t slaveid, uint8_t reg) {
return impl_->reg_read16(slaveid, reg);
}

25
drv_omap35x_i2c.hh Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _DRV_OMAP35X_I2C_HH_
#define _DRV_OMAP35X_I2C_HH_
#include <memory>
#include <cstdint>
class OMAP35x_I2C_impl;
#include "interfaces.hh"
class OMAP35x_I2C : public II2C {
public:
OMAP35x_I2C(uintptr_t base);
~OMAP35x_I2C();
virtual void reg_write(uint8_t slaveid, uint8_t reg, uint8_t value);
virtual uint8_t reg_read(uint8_t slaveid, uint8_t reg);
virtual void reg_write16(uint8_t slaveid, uint8_t reg, uint16_t value);
virtual uint16_t reg_read16(uint8_t slaveid, uint8_t reg);
private:
std::unique_ptr<OMAP35x_I2C_impl> impl_;
};
#endif

69
drv_tps65950.cc Normal file
View File

@@ -0,0 +1,69 @@
#include <memory>
#include <cstdint>
#include <cstdio>
#include <cassert>
#include "interfaces.hh"
#include "drv_tps65950.hh"
// OPP 0 1 2 3 4 5 6
// ARM Freq ret 125 250 500 550 600 720
// IVA2 Freq ret 90 180 360 400 430 520
static const uint8_t cpu_opp_volt[] = { 31, 31, 37, 48, 54, 60, 60};
// OPP 0 1 2 3
static const uint8_t core_opp_volt[] = { 31, 31, 37, 44};
class TPS65950_impl {
public:
TPS65950_impl(II2C& i2c) : i2c_(i2c) {
i2c_.reg_write(0x49, 0x97, 0x49);
uint8_t idcode[4];
for(int i = 0;i < 4;++i)
idcode[i] = i2c_.reg_read(0x49, 0x85+i);
uint8_t dieid[8];
for(int i = 0;i < 8;++i)
dieid[i] = i2c_.reg_read(0x49, 0x89+i);
printf("TPS65950 IDCODE: %.2hhu%.2hhu%.2hhu%.2hhu\n",
idcode[3], idcode[2], idcode[1], idcode[0]);
printf("\tSerial# %.2hhu%.2hhu%.2hhu%.2hhu%.2hhu%.2hhu%.2hhu%.2hhu\n",
dieid[7], dieid[6], dieid[5], dieid[4],
dieid[3], dieid[2], dieid[1], dieid[0]);
}
~TPS65950_impl() {
}
void set_cpu_opp(int opp) {
assert(opp>=0 && opp<=6);
i2c_.reg_write(0x4b, 0xb9, cpu_opp_volt[opp]);
}
void set_core_opp(int opp) {
assert(opp>=0 && opp<=3);
i2c_.reg_write(0x4b, 0xc7, core_opp_volt[opp]);
}
private:
II2C& i2c_;
};
TPS65950::TPS65950(II2C& i2c) : impl_{new TPS65950_impl{i2c}} {
}
TPS65950::~TPS65950() {
}
void TPS65950::set_cpu_opp(int opp) {
impl_->set_cpu_opp(opp);
}
void TPS65950::set_core_opp(int opp) {
impl_->set_core_opp(opp);
}

22
drv_tps65950.hh Normal file
View File

@@ -0,0 +1,22 @@
#ifndef _DRV_TPS65950_HH_
#define _DRV_TPS65950_HH_
#include <memory>
class TPS65950_impl;
#include "interfaces.hh"
class TPS65950 {
public:
TPS65950(II2C& i2c);
~TPS65950();
void set_cpu_opp(int opp);
void set_core_opp(int opp);
private:
std::unique_ptr<TPS65950_impl> impl_;
};
#endif

View File

@@ -2,7 +2,14 @@
#define _EXCEPTIONS_HH_
namespace ex {
// A memory allocation, or virtual address space allocation, failed
class bad_alloc{};
// An operation timed out
class timeout{};
// An unexcpected fatal error occured
class error{};
}
#endif

21
interfaces.hh Normal file
View File

@@ -0,0 +1,21 @@
#ifndef _INTERFACES_HH_
#define _INTERFACES_HH_
#include <cstdint>
class ICharacterDevice {
public:
virtual void write(char const* data, int const& len) = 0;
virtual int read(char *buf, int const& len) = 0;
};
class II2C {
public:
virtual void reg_write(uint8_t slaveid, uint8_t reg, uint8_t value) = 0;
virtual uint8_t reg_read(uint8_t slaveid, uint8_t reg) = 0;
virtual void reg_write16(uint8_t slaveid, uint8_t reg, uint16_t value) = 0;
virtual uint16_t reg_read16(uint8_t slaveid, uint8_t reg) = 0;
};
#endif

17
main.cc
View File

@@ -5,6 +5,8 @@
#include <malloc.h>
#include "drv_omap35x_gpt.hh"
#include "drv_omap35x_i2c.hh"
#include "drv_tps65950.hh"
#include "omap35x.hh"
#include "omap35x_intc.hh"
#include "omap35x_prcm.hh"
@@ -13,6 +15,8 @@
#include "cortexa8.hh"
#include "uart.hh"
void sbrk_stats();
static volatile uint32_t tickctr = 0;
static OMAP35x_prcm* _prcm = nullptr;
void tickfunc() noexcept {
@@ -66,13 +70,21 @@ int main(int argc, char* argv[]) {
chipInfo.print_chip_id();
printf("5\n");
if(chipInfo.running_on_qemu())
printf("QEMU detected, avoiding bugs...\n");
OMAP35x_GPT gpt2{0x49032000, 38};
gpt2.ticktimer(&tickfunc);
printf("6\n");
// Configure TPS65950 (power control etc.)
OMAP35x_I2C i2c1{0x48070000};
TPS65950 tps65950{i2c1};
if(!chipInfo.running_on_qemu()) {
prcm.set_cpu_opp(3);
tps65950.set_cpu_opp(3);
}
while(1) {
char buf[256];
@@ -85,6 +97,7 @@ int main(int argc, char* argv[]) {
}
malloc_stats();
sbrk_stats();
phys_mm::print_state();
while(1) {

View File

@@ -11,9 +11,12 @@ using std::printf;
static const char *const omap_names[5] = {"OMAP3530", "OMAP3525", "OMAP3515", "OMAP3503", "UNKNOWN"};
static const char *const omap_ver[8] = {"ES 1.0", "ES 2.0", "ES 2.1", "ES 3.0", "ES 3.1", "UNKNOWN", "UNKNOWN", "ES 3.1.2"};
static std::array<uint32_t, 4> qemu_serial = {0x51454d55, 0x51454d55, 0x54000000, 0x51454d55};
class OMAP35x_Info_impl {
public:
OMAP35x_Info_impl(uintptr_t scm_base, uintptr_t control_base) : scm_base_{scm_base}, control_base_{control_base} {
OMAP35x_Info_impl(uintptr_t scm_base, uintptr_t control_base)
: scm_base_{scm_base}, control_base_{control_base}, serial_(_get_serial()) {
}
~OMAP35x_Info_impl() {
@@ -55,15 +58,24 @@ public:
printf("%s %s %s Serial# %.8lx%.8lx%.8lx%.8lx\n",
omap_names[omapsr_idx], omap_ver[id_idx],
highfreq?"720 MHz":"600 MHz",
r_die_id(3), r_die_id(2), r_die_id(1), r_die_id(0));
serial_[0], serial_[1], serial_[2], serial_[3]);
}
std::array<uint32_t, 4> get_serial() {
return std::array<uint32_t, 4>{r_die_id(3), r_die_id(2), r_die_id(1), r_die_id(0)};
bool running_on_qemu() const {
return (serial_ == qemu_serial);
}
std::array<uint32_t, 4> const& get_serial() const {
return serial_;
}
private:
std::array<uint32_t, 4> _get_serial() {
return std::array<uint32_t, 4>{r_die_id(3), r_die_id(2), r_die_id(1), r_die_id(0)};
}
MMIO_alloc scm_base_, control_base_;
std::array<uint32_t, 4> serial_;
uint32_t volatile& r_omap_sr() { return _reg32(scm_base_.get_virt(), 0x44c); }
uint32_t volatile& r_idcode() { return _reg32(control_base_.get_virt(), 0x204); }
@@ -81,3 +93,7 @@ OMAP35x_Info::~OMAP35x_Info() {
void OMAP35x_Info::print_chip_id() {
impl_->print_chip_id();
}
bool OMAP35x_Info::running_on_qemu() const {
return impl_->running_on_qemu();
}

View File

@@ -12,6 +12,8 @@ public:
void print_chip_id();
bool running_on_qemu() const;
private:
std::unique_ptr<OMAP35x_Info_impl> impl_;
};

View File

@@ -9,7 +9,7 @@
#include "omap35x_intc.hh"
extern "C" void _omap35x_intc_handler() __attribute__((interrupt ("IRQ")));
extern "C" void _omap35x_intc_handler();
static OMAP35x_intc_impl* intc = nullptr;
class OMAP35x_intc_impl {

View File

@@ -6,9 +6,13 @@
#include "mmio.hh"
#include "omap35x_prcm.hh"
static const unsigned cpu_opp_freq[] = {0, 125, 250, 500, 550, 600, 720};
static const unsigned iva2_opp_freq[] = {0, 45, 90, 180, 200, 215, 260};
class OMAP35x_prcm_impl {
public:
OMAP35x_prcm_impl(uintptr_t cm_base, uintptr_t pm_base) :cm_base_{cm_base, 28}, pm_base_{pm_base, 42} {
OMAP35x_prcm_impl(uintptr_t cm_base, uintptr_t pm_base)
: cm_base_{cm_base, 28}, pm_base_{pm_base, 42}, cpu_opp_{2}, enable_iva2_{false} {
// Setup IVA2 domain (unused, disable)
r_clkstctrl_iva2() = 0x3;
r_wkdep_iva2() = 0;
@@ -19,10 +23,13 @@ public:
// Setup CORE domain (enable)
r_clkstctrl_core() = 0xf; // Autosleep L3&L4
r_iva2grpsel1_core() = 0x80000008;
r_iva2grpsel3_core() = 0x00000000;
// Setup PER domain (enable)
r_sleepdep_per() |= (1<<1); // Enable PER-MPU sleep dep.
r_clkstctrl_per() |= 0x3; // Enable autosleep
r_iva2grpsel_per() = 0x00000000;
// Setup SGX domain (unused, disable)
r_clkstctrl_sgx() = 0x3;
@@ -63,6 +70,12 @@ public:
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
// Prepare I2C1
r_fclken1_core() |= (1<<15);
r_iclken1_core() |= (1<<15);
r_autoidle1_core() |= (1<<15);
r_wken1_core() &= ~(1<15);
}
void clear_wake_per(int n) {
@@ -70,9 +83,45 @@ public:
r_wkst_per() = (1<<n);
}
void set_cpu_opp(int opp) {
assert(opp >= 1 && opp <= 6);
r_clken_pll_mpu() = 0x75;
uint32_t clksel = 0x01000000;
if(opp == 1)
clksel = 0x02000000; // Bypass must be /4 for OPP1
clksel |= 12;
clksel |= cpu_opp_freq[opp]<<8;
r_clksel1_pll_mpu() = clksel;
r_clken_pll_mpu() = 0x77;
if(enable_iva2_) {
r_clken_pll_iva2() = 0x75;
clksel = 0x01000000;
clksel |= 12;
clksel |= iva2_opp_freq[opp]<<8;
r_clksel1_pll_iva2() = clksel;
r_clken_pll_iva2() = 0x77;
}
cpu_opp_ = opp;
}
void set_core_opp(int opp, int config) {
}
private:
MMIO_alloc cm_base_, pm_base_;
//uintptr_t cm_base_, pm_base_;
int cpu_opp_;
bool enable_iva2_;
// CM registers
uint32_t volatile& r_fclken_iva2() { return _reg32(cm_base_.get_virt(), 0x0); }
@@ -201,8 +250,8 @@ private:
uint32_t volatile& r_pwstst_core() {return _reg32(pm_base_.get_virt(), 0xae4); }
uint32_t volatile& r_prepwstst_core() {return _reg32(pm_base_.get_virt(), 0xae8); }
uint32_t volatile& r_wken3_core() {return _reg32(pm_base_.get_virt(), 0xaf0); }
uint32_t volatile& r_iva2grpsel2_core() {return _reg32(pm_base_.get_virt(), 0xaf4); }
uint32_t volatile& r_mpugrpsel2_core() {return _reg32(pm_base_.get_virt(), 0xaf8); }
uint32_t volatile& r_iva2grpsel3_core() {return _reg32(pm_base_.get_virt(), 0xaf4); }
uint32_t volatile& r_mpugrpsel3_core() {return _reg32(pm_base_.get_virt(), 0xaf8); }
uint32_t volatile& r_rstst_sgx() {return _reg32(pm_base_.get_virt(), 0xb58); }
uint32_t volatile& r_wkdep_sgx() {return _reg32(pm_base_.get_virt(), 0xbc8); }
@@ -269,3 +318,11 @@ void OMAP35x_prcm::enable_peripherals() {
void OMAP35x_prcm::clear_wake_per(int n) {
impl_->clear_wake_per(n);
}
void OMAP35x_prcm::set_cpu_opp(int opp) {
impl_->set_cpu_opp(opp);
}
void OMAP35x_prcm::set_core_opp(int opp, int config) {
impl_->set_core_opp(opp, config);
}

View File

@@ -15,6 +15,9 @@ public:
void clear_wake_per(int n);
void set_cpu_opp(int opp);
void set_core_opp(int opp, int config);
private:
std::unique_ptr<OMAP35x_prcm_impl> impl_;
};

View File

@@ -69,11 +69,11 @@ int _write(int file, const char *ptr, int len) {
}
extern uint32_t __heap_start;
static uintptr_t heap_end = 0;
static uintptr_t brk;
caddr_t _sbrk(int incr) __attribute__((used));
caddr_t _sbrk(int incr) {
static uintptr_t heap_end = 0;
static uintptr_t brk;
if(heap_end == 0) {
heap_end = mm::get_heap_end();
brk = (uintptr_t)&__heap_start;
@@ -113,6 +113,28 @@ int _open(const char *name, int flags, int mode) {
return -1;
}
/* struct _reent* __getreent() __attribute__((used)); */
/* struct _reent* __getreent() { */
/* _write(1,"!", 1); */
/* return nullptr; */
/* } */
#ifdef __cplusplus
}
#endif
#include <cstdio>
void sbrk_stats() {
if(heap_end == 0) {
_write(1, "Heap not initialized\n", 21);
return;
}
uintptr_t save_heap_end = heap_end, save_brk = brk;
printf("Heap: %u bytes allocated, %u bytes used\n",
save_heap_end-(uintptr_t)&__heap_start,
save_brk-(uintptr_t)&__heap_start);
}

View File

@@ -6,11 +6,7 @@
class OMAP35x_prcm;
class ICharacterDevice {
public:
virtual void write(char const* data, int const& len) = 0;
virtual int read(char *buf, int const& len) = 0;
};
#include "interfaces.hh"
class UART_impl;