-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:
4
Makefile
4
Makefile
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -109,6 +109,33 @@ cortexa8_set_fiq_sp:
|
||||
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
|
||||
@@ -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
213
drv_omap35x_i2c.cc
Normal 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
25
drv_omap35x_i2c.hh
Normal 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
69
drv_tps65950.cc
Normal 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
22
drv_tps65950.hh
Normal 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
|
||||
@@ -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
21
interfaces.hh
Normal 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
17
main.cc
@@ -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) {
|
||||
|
||||
24
omap35x.cc
24
omap35x.cc
@@ -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();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ public:
|
||||
|
||||
void print_chip_id();
|
||||
|
||||
bool running_on_qemu() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<OMAP35x_Info_impl> impl_;
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
30
syscall.c
30
syscall.c
@@ -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;
|
||||
@@ -95,7 +95,7 @@ caddr_t _sbrk(int incr) {
|
||||
caddr_t prev_brk = (caddr_t)brk;
|
||||
brk += incr;
|
||||
return prev_brk;
|
||||
}
|
||||
}
|
||||
|
||||
int _kill(int pid, int sig) __attribute__((used));
|
||||
int _kill(int pid, int sig) {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user