registers working

This commit is contained in:
Tony Kuker 2022-09-10 20:30:27 +00:00
parent 68a95794da
commit f5ee073eaf
23 changed files with 2212 additions and 127 deletions

View File

@ -18,11 +18,11 @@ CXX = $(CROSS_COMPILE)g++
DEBUG ?= 0
ifeq ($(DEBUG), 1)
# Debug compiler flags
CXXFLAGS += -O0 -g -Wall -DDEBUG
CXXFLAGS += -O0 -g -DDEBUG
BUILD_TYPE = Debug
else
# Release compiler flags
CXXFLAGS += -O3 -Wall -Werror -DNDEBUG
CXXFLAGS += -O0 -g -DDEBUG
BUILD_TYPE = Release
endif
ifeq ("$(shell uname -s)","Linux")
@ -58,6 +58,7 @@ RASCTL = rasctl
RASDUMP = rasdump
SCSIMON = scsimon
RASCSI_TEST = rascsi_test
REGISTERS_TEST = registers
SYSTEMD_CONF = /etc/systemd/system/rascsi.service
RSYSLOG_CONF = /etc/rsyslog.d/rascsi.conf
@ -204,6 +205,9 @@ $(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
$(REGISTERS_TEST): registers.c
$(CXX) $(CXXFLAGS) -o $@ $<
# Phony rules for building individual utilities
.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SCSIMON)
@ -217,7 +221,7 @@ $(SCSIMON) : $(BINDIR)/$(SCSIMON)
## compiler files and executable files
.PHONY: clean
clean:
rm -rf $(OBJDIR) $(BINDIR) $(GEN_PROTOBUF) $(COVERAGE_DIR) $(COVERAGE_FILE)
rm -rf $(OBJDIR) $(BINDIR) $(GEN_PROTOBUF) $(COVERAGE_DIR) $(COVERAGE_FILE) $(REGISTERS_TEST)
## install : Copies all of the man pages to the correct location
## Copies the binaries to a global install location

48
src/raspberrypi/common.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2012 Alejandro Mery <amery@geeks.cl>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SUNXI_TOOLS_COMMON_H
#define _SUNXI_TOOLS_COMMON_H
#include <stddef.h> /* offsetof */
#include "version.h" /* auto-generated VERSION string */
/** flag function argument as unused */
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#else
# define UNUSED(x) UNUSED_ ## x
#endif
/** finds the parent of an struct member */
#ifndef container_of
#define container_of(P,T,M) (T *)((char *)(P) - offsetof(T, M))
#endif
/** calculate number of elements of an array */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
/** shortcut to "printf to stderr" */
#define pr_error(...) fprintf(stderr, __VA_ARGS__)
/** like pr_error(), but also exit program */
#define pr_fatal(...) \
do { pr_error(__VA_ARGS__); exit(EXIT_FAILURE); } while (0);
#endif /* _SUNXI_TOOLS_COMMON_H */

View File

@ -292,7 +292,7 @@ void ScsiController::Execute()
// Initialization for data transfer
ctrl.offset = 0;
ctrl.blocks = 1;
execstart = SysTimer::GetTimerLow();
execstart = SysTimer::instance().GetTimerLow();
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
@ -356,7 +356,7 @@ void ScsiController::Status()
if (execstart > 0) {
Sleep();
} else {
SysTimer::SleepUsec(5);
SysTimer::instance().SleepUsec(5);
}
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.status)
@ -1220,8 +1220,8 @@ int ScsiController::GetEffectiveLun() const
void ScsiController::Sleep()
{
if (uint32_t time = SysTimer::GetTimerLow() - execstart; time < MIN_EXEC_TIME) {
SysTimer::SleepUsec(MIN_EXEC_TIME - time);
if (uint32_t time = SysTimer::instance().GetTimerLow() - execstart; time < MIN_EXEC_TIME) {
SysTimer::instance().SleepUsec(MIN_EXEC_TIME - time);
}
execstart = 0;
}

View File

View File

View File

@ -705,7 +705,7 @@ int GPIOBUS::CommandHandShake(BYTE *buf)
bool ret = WaitSignal(PIN_ACK, TRUE);
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
SysTimer::instance.SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
@ -742,7 +742,7 @@ int GPIOBUS::CommandHandShake(BYTE *buf)
ret = WaitSignal(PIN_ACK, TRUE);
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
SysTimer::instance.SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get the actual SCSI command
*buf = GetDAT();
@ -776,7 +776,7 @@ int GPIOBUS::CommandHandShake(BYTE *buf)
ret = WaitSignal(PIN_ACK, TRUE);
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
SysTimer::instance.SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
@ -827,7 +827,7 @@ int GPIOBUS::ReceiveHandShake(BYTE *buf, int count)
bool ret = WaitSignal(PIN_ACK, TRUE);
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
SysTimer::instance.SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
@ -870,7 +870,7 @@ int GPIOBUS::ReceiveHandShake(BYTE *buf, int count)
}
// Wait until the signal line stabilizes
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
SysTimer::instance.SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
// Get data
*buf = GetDAT();
@ -922,7 +922,7 @@ int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
for (i = 0; i < count; i++) {
if(i==delay_after_bytes){
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes)
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
SysTimer::instance.SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
}
// Set the DATA signals
@ -965,7 +965,7 @@ int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
for (i = 0; i < count; i++) {
if(i==delay_after_bytes){
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes)
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
SysTimer::instance.SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
}
// Set the DATA signals
@ -1366,9 +1366,9 @@ void GPIOBUS::PullConfig(int pin, int mode)
} else {
pin &= 0x1f;
gpio[GPIO_PUD] = mode & 0x3;
SysTimer::SleepUsec(2);
SysTimer::instance.SleepUsec(2);
gpio[GPIO_CLK_0] = 0x1 << pin;
SysTimer::SleepUsec(2);
SysTimer::instance.SleepUsec(2);
gpio[GPIO_PUD] = 0;
gpio[GPIO_CLK_0] = 0;
}

View File

@ -0,0 +1,203 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 akuker
//
// [ Hardware version detection routines ]
//
//---------------------------------------------------------------------------
#include "sbc_version.h"
#include "log.h"
#include <iostream>
#include <fstream>
#include <sstream>
SBC_Version::sbc_version_type SBC_Version::m_sbc_version = SBC_Version::sbc_unknown;
// const std::string SBC_Version::m_str_raspberry_pi_1 = "Raspberry Pi 1";
// const std::string SBC_Version::m_str_raspberry_pi_2_3 = "Raspberry Pi 2/3";
// const std::string SBC_Version::m_str_raspberry_pi_4 = "Raspberry Pi 4";
// const std::string SBC_Version::m_str_bananapi_m2_berry = "Banana Pi M2 Berry/Ultra";
// const std::string SBC_Version::m_str_bananapi_m2_zero = "Banana Pi M2 Zero";
// const std::string SBC_Version::m_str_bananapi_m2_plus = "Banana Pi BPI-M2-Plus H3";
// const std::string SBC_Version::m_str_bananapi_m3 = "Banana Pi M3";
// const std::string SBC_Version::m_str_bananapi_m4 = "Banana Pi M4";
// const std::string SBC_Version::m_str_unknown_sbc = "Unknown SBC";
// The strings in this table should align with the 'model' embedded
// in the device tree. This can be aquired by running:
// cat /proc/device-tree/model
// Only the first part of the string is checked. Anything following
// will be ignored. For example:
// "Raspberry Pi 4 Model B" will match with both of the following:
// - Raspberry Pi 4 Model B Rev 1.4
// - Raspberry Pi 4 Model B Rev 1.3
const std::map<std::string, SBC_Version::sbc_version_type> SBC_Version::m_proc_device_tree_mapping = {
{"Raspberry Pi 1 Model ", SBC_Version::sbc_raspberry_pi_1},
{"Raspberry Pi 2 Model ", SBC_Version::sbc_raspberry_pi_2_3},
{"Raspberry Pi 3 Model ", SBC_Version::sbc_raspberry_pi_2_3},
{"Raspberry Pi 4 Model ", SBC_Version::sbc_raspberry_pi_4},
{"Raspberry Pi 400 ", SBC_Version::sbc_raspberry_pi_4},
{"Raspberry Pi Zero W", SBC_Version::sbc_raspberry_pi_1},
{"Raspberry Pi Zero", SBC_Version::sbc_raspberry_pi_1},
{"Banana Pi BPI-M2-Zero ", SBC_Version::sbc_bananapi_m2_zero},
{"Banana Pi BPI-M2-Ultra ", SBC_Version::sbc_bananapi_m2_berry},
{"Banana Pi BPI-M2-Plus H3", SBC_Version::sbc_bananapi_m2_plus},
{"Banana Pi M2 Berry ", SBC_Version::sbc_bananapi_m2_berry},
// sbc_bananapi_m3, TBD....
// sbc_bananapi_m4,
};
const std::string SBC_Version::m_device_tree_model_path = "/proc/device-tree/model";
//---------------------------------------------------------------------------
//
// Convert the SBC Version to a printable string
//
//---------------------------------------------------------------------------
const std::string* SBC_Version::GetString(){
switch(m_sbc_version){
case sbc_raspberry_pi_1: return &m_str_raspberry_pi_1;
case sbc_raspberry_pi_2_3: return &m_str_raspberry_pi_2_3;
case sbc_raspberry_pi_4: return &m_str_raspberry_pi_4;
case sbc_bananapi_m2_berry: return &m_str_bananapi_m2_berry;
case sbc_bananapi_m2_zero: return &m_str_bananapi_m2_zero;
case sbc_bananapi_m3: return &m_str_bananapi_m3;
case sbc_bananapi_m4: return &m_str_bananapi_m4;
default:
LOGERROR("Unknown type of sbc detected: %d",m_sbc_version);
return &m_str_unknown_sbc;
}
}
SBC_Version::sbc_version_type SBC_Version::GetSbcVersion(){
return m_sbc_version;
}
//---------------------------------------------------------------------------
//
// Determine which version of single board computer (Pi) is being used
// based upon the device tree model string.
//
//---------------------------------------------------------------------------
void SBC_Version::Init(){
std::string device_tree_model;
const std::ifstream input_stream(SBC_Version::m_device_tree_model_path);
if (input_stream.fail()) {
LOGERROR("Failed to open %s. Are you running as root?", SBC_Version::m_device_tree_model_path.c_str());
throw std::runtime_error("Failed to open /proc/device-tree/model");
}
std::stringstream str_buffer;
str_buffer << input_stream.rdbuf();
device_tree_model = str_buffer.str();
for (const auto& [key, value] : m_device_model_map) {
if(device_tree_model.rfind(key,0) == 0){
m_sbc_version = value;
LOGINFO("Detected device %s", GetString()->c_str());
return;
}
}
LOGERROR("%s Unable to determine single board computer type. Defaulting to Raspberry Pi 4", __PRETTY_FUNCTION__);
m_sbc_version = sbc_version_type::sbc_raspberry_pi_4;
}
bool SBC_Version::IsRaspberryPi(){
switch(m_sbc_version){
case sbc_raspberry_pi_1:
case sbc_raspberry_pi_2_3:
case sbc_raspberry_pi_4:
return true;
case sbc_bananapi_m2_berry:
case sbc_bananapi_m2_zero:
case sbc_bananapi_m2_plus:
case sbc_bananapi_m3:
case sbc_bananapi_m4:
return false;
default:
return false;
}
}
bool SBC_Version::IsBananaPi(){
switch(m_sbc_version){
case sbc_raspberry_pi_1:
case sbc_raspberry_pi_2_3:
case sbc_raspberry_pi_4:
return false;
case sbc_bananapi_m2_berry:
case sbc_bananapi_m2_zero:
case sbc_bananapi_m2_plus:
case sbc_bananapi_m3:
case sbc_bananapi_m4:
return true;
default:
return false;
}
}
//---------------------------------------------------------------------------
//
// imported from bcm_host.c
//
//---------------------------------------------------------------------------
DWORD SBC_Version::GetDeviceTreeRanges(const char *filename, DWORD offset)
{
DWORD address = ~0;
if (FILE *fp = fopen(filename, "rb"); fp) {
fseek(fp, offset, SEEK_SET);
if (BYTE buf[4]; fread(buf, 1, sizeof buf, fp) == sizeof buf) {
address =
buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
}
fclose(fp);
}
return address;
}
#if defined __linux__
DWORD SBC_Version::GetPeripheralAddress(void)
{
DWORD address = GetDeviceTreeRanges("/proc/device-tree/soc/ranges", 4);
if (address == 0) {
address = GetDeviceTreeRanges("/proc/device-tree/soc/ranges", 8);
}
address = (address == (DWORD)~0) ? 0x20000000 : address;
printf("Peripheral address : 0x%8x\n", address);
return address;
}
#elif defined __NetBSD__
DWORD SBC_Version::GetPeripheralAddress(void)
{
char buf[1024];
size_t len = sizeof(buf);
DWORD address;
if (sysctlbyname("hw.model", buf, &len, NULL, 0) ||
strstr(buf, "ARM1176JZ-S") != buf) {
// Failed to get CPU model || Not BCM2835
// use the address of BCM283[67]
address = 0x3f000000;
} else {
// Use BCM2835 address
address = 0x20000000;
}
printf("Peripheral address : 0x%lx\n", address);
return address;
}
#else
DWORD SBC_Version::GetPeripheralAddress(void)
{
return 0;
}
#endif

View File

@ -0,0 +1,68 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 akuker
//
// [ Hardware version detection routines ]
//
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include <string>
#include <map>
//===========================================================================
//
// Single Board Computer Versions
//
//===========================================================================
class SBC_Version
{
public:
// Type of Single Board Computer
enum sbc_version_type : uint8_t {
sbc_unknown = 0,
sbc_raspberry_pi_1,
sbc_raspberry_pi_2_3,
sbc_raspberry_pi_4,
sbc_bananapi_m2_berry,
sbc_bananapi_m2_zero,
sbc_bananapi_m2_plus,
sbc_bananapi_m3,
sbc_bananapi_m4,
};
static void Init();
static sbc_version_type GetSbcVersion();
static bool IsRaspberryPi();
static bool IsBananaPi();
static const std::string* GetString();
static DWORD GetPeripheralAddress();
private:
static sbc_version_type m_sbc_version;
static const std::string m_str_raspberry_pi_1;
static const std::string m_str_raspberry_pi_2_3;
static const std::string m_str_raspberry_pi_4;
static const std::string m_str_bananapi_m2_berry;
static const std::string m_str_bananapi_m2_zero;
static const std::string m_str_bananapi_m2_plus;
static const std::string m_str_bananapi_m3;
static const std::string m_str_bananapi_m4;
static const std::string m_str_unknown_sbc;
static const std::map<std::string, sbc_version_type> m_proc_device_tree_mapping;
static const std::string m_device_tree_model_path;
static DWORD GetDeviceTreeRanges(const char *filename, DWORD offset);
};

View File

@ -20,115 +20,34 @@
#include "config.h"
#include "log.h"
//---------------------------------------------------------------------------
//
// System timer address
//
//---------------------------------------------------------------------------
volatile DWORD* SysTimer::systaddr;
//---------------------------------------------------------------------------
//
// ARM timer address
//
//---------------------------------------------------------------------------
volatile DWORD* SysTimer::armtaddr;
static std::shared_ptr<SysTimer> private_instance = nullptr;
//---------------------------------------------------------------------------
//
// Core frequency
//
//---------------------------------------------------------------------------
volatile DWORD SysTimer::corefreq;
//---------------------------------------------------------------------------
//
// Initialize the system timer
//
//---------------------------------------------------------------------------
void SysTimer::Init(DWORD *syst, DWORD *armt)
ControllerManager& ControllerManager::instance()
{
// RPI Mailbox property interface
// Get max clock rate
// Tag: 0x00030004
//
// Request: Length: 4
// Value: u32: clock id
// Response: Length: 8
// Value: u32: clock id, u32: rate (in Hz)
//
// Clock id
// 0x000000004: CORE
DWORD maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
// Save the base address
systaddr = syst;
armtaddr = armt;
// Change the ARM timer to free run mode
armtaddr[ARMT_CTRL] = 0x00000282;
// Get the core frequency
corefreq = 0;
int fd = open("/dev/vcio", O_RDONLY);
if (fd >= 0) {
ioctl(fd, _IOWR(100, 0, char *), maxclock);
corefreq = maxclock[6] / 1000000;
// If we haven't set up the private instance yet, do that now
if(private_instance == nullptr){
if(SBC_Version::IsRaspberryPi()){
private_instance = std::make_shared<SysTimer_Raspberry>();
private_instance->Init();
}
else if(SBC_Version::IsBananaPi()){
private_instance = std::make_shared<SysTimer_AllWinner>();
private_instance->Init();
}
}
close(fd);
return private_instance;
}
//---------------------------------------------------------------------------
//
// Get system timer low byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerLow() {
return systaddr[SYST_CLO];
}
//---------------------------------------------------------------------------
//
// Get system timer high byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerHigh() {
return systaddr[SYST_CHI];
}
//---------------------------------------------------------------------------
//
// Sleep in nanoseconds
//
//---------------------------------------------------------------------------
void SysTimer::SleepNsec(DWORD nsec)
{
// If time is 0, don't do anything
if (nsec == 0) {
return;
}
// Calculate the timer difference
DWORD diff = corefreq * nsec / 1000;
// Return if the difference in time is too small
if (diff == 0) {
return;
}
// Start
DWORD start = armtaddr[ARMT_FREERUN];
// Loop until timer has elapsed
while ((armtaddr[ARMT_FREERUN] - start) < diff);
}
//---------------------------------------------------------------------------
//
// Sleep in microseconds
//
//---------------------------------------------------------------------------
void SysTimer::SleepUsec(DWORD usec)
void SysTimer::instance.SleepUsec(DWORD usec)
{
// If time is 0, don't do anything
if (usec == 0) {

View File

@ -26,22 +26,16 @@
class SysTimer
{
public:
static void Init(uint32_t *syst, uint32_t *armt);
// Initialization
static uint32_t GetTimerLow();
virtual uint32_t GetTimerLow();
// Get system timer low byte
static uint32_t GetTimerHigh();
virtual uint32_t GetTimerHigh();
// Get system timer high byte
static void SleepNsec(uint32_t nsec);
virtual void SleepNsec(uint32_t nsec);
// Sleep for N nanoseconds
static void SleepUsec(uint32_t usec);
virtual void SleepUsec(uint32_t usec);
// Sleep for N microseconds
static SysTimer& instance();
private:
static volatile uint32_t *systaddr;
// System timer address
static volatile uint32_t *armtaddr;
// ARM timer address
static volatile uint32_t corefreq;
// Core frequency
static std::shared_ptr<SysTimer> private_instance;
};

View File

@ -0,0 +1,136 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2022 akuker
//
// [ High resolution timer ]
//
//---------------------------------------------------------------------------
#include "hal/systimer.h"
#include <sys/mman.h>
#include "os.h"
#include "hal/gpiobus.h"
#include "config.h"
#include "log.h"
ControllerManager& ControllerManager::instance()
{
// If we haven't set up the private instance yet, do that now
if(private_instance == nullptr){
if(SBC_Version::IsRaspberryPi()){
private_instance = std::make_shared<SysTimer_Raspberry>();
private_instance->Init();
}
else if(SBC_Version::IsBananaPi()){
private_instance = std::make_shared<SysTimer_AllWinner>();
private_instance->Init();
}
}
return private_instance;
}
//---------------------------------------------------------------------------
//
// Initialize the system timer
//
//---------------------------------------------------------------------------
void SysTimer::Init(DWORD *syst, DWORD *armt)
{
// RPI Mailbox property interface
// Get max clock rate
// Tag: 0x00030004
//
// Request: Length: 4
// Value: u32: clock id
// Response: Length: 8
// Value: u32: clock id, u32: rate (in Hz)
//
// Clock id
// 0x000000004: CORE
DWORD maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
// Save the base address
systaddr = syst;
armtaddr = armt;
// Change the ARM timer to free run mode
armtaddr[ARMT_CTRL] = 0x00000282;
// Get the core frequency
corefreq = 0;
int fd = open("/dev/vcio", O_RDONLY);
if (fd >= 0) {
ioctl(fd, _IOWR(100, 0, char *), maxclock);
corefreq = maxclock[6] / 1000000;
}
close(fd);
}
//---------------------------------------------------------------------------
//
// Get system timer low byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerLow() {
return systaddr[SYST_CLO];
}
//---------------------------------------------------------------------------
//
// Get system timer high byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerHigh() {
return systaddr[SYST_CHI];
}
//---------------------------------------------------------------------------
//
// Sleep in nanoseconds
//
//---------------------------------------------------------------------------
void SysTimer::instance.SleepNsec(DWORD nsec)
{
// If time is 0, don't do anything
if (nsec == 0) {
return;
}
// Calculate the timer difference
DWORD diff = corefreq * nsec / 1000;
// Return if the difference in time is too small
if (diff == 0) {
return;
}
// Start
DWORD start = armtaddr[ARMT_FREERUN];
// Loop until timer has elapsed
while ((armtaddr[ARMT_FREERUN] - start) < diff);
}
//---------------------------------------------------------------------------
//
// Sleep in microseconds
//
//---------------------------------------------------------------------------
void SysTimer::instance.SleepUsec(DWORD usec)
{
// If time is 0, don't do anything
if (usec == 0) {
return;
}
DWORD now = GetTimerLow();
while ((GetTimerLow() - now) < usec);
}

View File

@ -0,0 +1,42 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 akuker
//
// [ High resolution timer ]
//
//---------------------------------------------------------------------------
#pragma once
#include <stdint.h>
#include "systimer.h"
//===========================================================================
//
// System timer
//
//===========================================================================
class SysTimer_AllWinner : SysTimer
{
public:
override void Init(uint32_t *syst, uint32_t *armt);
// Initialization
override uint32_t GetTimerLow();
// Get system timer low byte
override uint32_t GetTimerHigh();
// Get system timer high byte
override void SleepNsec(uint32_t nsec);
// Sleep for N nanoseconds
override void SleepUsec(uint32_t usec);
// Sleep for N microseconds
private:
static volatile uint32_t *systaddr;
// System timer address
static volatile uint32_t *armtaddr;
// ARM timer address
static volatile uint32_t corefreq;
// Core frequency
};

View File

@ -0,0 +1,153 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2022 akuker
//
// [ High resolution timer ]
//
//---------------------------------------------------------------------------
#include "hal/systimer.h"
#include <sys/mman.h>
#include "os.h"
#include "hal/gpiobus.h"
#include "config.h"
#include "log.h"
ControllerManager& ControllerManager::instance()
{
// If we haven't set up the private instance yet, do that now
if(private_instance == nullptr){
if(SBC_Version::IsRaspberryPi()){
private_instance = std::make_shared<SysTimer_Raspberry>();
private_instance->Init();
}
else if(SBC_Version::IsBananaPi()){
private_instance = std::make_shared<SysTimer_AllWinner>();
private_instance->Init();
}
}
return private_instance;
}
//---------------------------------------------------------------------------
//
// Initialize the system timer
//
//---------------------------------------------------------------------------
void SysTimer_Raspberry::Init()
{
// Get the base address
// auto baseaddr = (DWORD)bcm_host_get_peripheral_address();
auto baseaddr = SBC_Version::GetPeripheralAddress();
// Open /dev/mem
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
LOGERROR("Error: Unable to open /dev/mem. Are you running as root?")
return;
}
// Map peripheral region memory
map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
if (map == MAP_FAILED) {
LOGERROR("Error: Unable to map memory")
close(fd);
return;
}
// RPI Mailbox property interface
// Get max clock rate
// Tag: 0x00030004
//
// Request: Length: 4
// Value: u32: clock id
// Response: Length: 8
// Value: u32: clock id, u32: rate (in Hz)
//
// Clock id
// 0x000000004: CORE
DWORD maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
// Save the base address
systaddr = (DWORD *)map + SYST_OFFSET / sizeof(DWORD);
armtaddr = (DWORD *)map + ARMT_OFFSET / sizeof(DWORD));
// Change the ARM timer to free run mode
armtaddr[ARMT_CTRL] = 0x00000282;
// Get the core frequency
if (int fd = open("/dev/vcio", O_RDONLY); fd >= 0) {
ioctl(fd, _IOWR(100, 0, char *), maxclock);
corefreq = maxclock[6] / 1000000;
close(fd);
}
}
//---------------------------------------------------------------------------
//
// Get system timer low byte
//
//---------------------------------------------------------------------------
DWORD SysTimer_Raspberry::GetTimerLow() {
return systaddr[SYST_CLO];
}
//---------------------------------------------------------------------------
//
// Get system timer high byte
//
//---------------------------------------------------------------------------
DWORD SysTimer_Raspberry::GetTimerHigh() {
return systaddr[SYST_CHI];
}
//---------------------------------------------------------------------------
//
// Sleep in nanoseconds
//
//---------------------------------------------------------------------------
void SysTimer_Raspberry::SleepNsec(DWORD nsec)
{
// If time is 0, don't do anything
if (nsec == 0) {
return;
}
// Calculate the timer difference
DWORD diff = corefreq * nsec / 1000;
// Return if the difference in time is too small
if (diff == 0) {
return;
}
// Start
DWORD start = armtaddr[ARMT_FREERUN];
// Loop until timer has elapsed
while ((armtaddr[ARMT_FREERUN] - start) < diff);
}
//---------------------------------------------------------------------------
//
// Sleep in microseconds
//
//---------------------------------------------------------------------------
void SysTimer_Raspberry::SleepUsec(DWORD usec)
{
// If time is 0, don't do anything
if (usec == 0) {
return;
}
DWORD now = GetTimerLow();
while ((GetTimerLow() - now) < usec);
}

View File

@ -0,0 +1,45 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2022 akuker
//
// [ High resolution timer ]
//
//---------------------------------------------------------------------------
#pragma once
#include <stdint.h>
#include "systimer.h"
//===========================================================================
//
// System timer
//
//===========================================================================
class SysTimer_Raspberry : SysTimer
{
public:
override void Init(uint32_t *syst, uint32_t *armt);
// Initialization
override uint32_t GetTimerLow();
// Get system timer low byte
override uint32_t GetTimerHigh();
// Get system timer high byte
override void SleepNsec(uint32_t nsec);
// Sleep for N nanoseconds
override void SleepUsec(uint32_t usec);
// Sleep for N microseconds
private:
static volatile uint32_t *systaddr;
// System timer address
static volatile uint32_t *armtaddr;
// ARM timer address
static volatile uint32_t corefreq = 0;
// Core frequency
};

BIN
src/raspberrypi/mem-info Executable file

Binary file not shown.

793
src/raspberrypi/mem-info.c Normal file
View File

@ -0,0 +1,793 @@
/*
* Copyright (C) 2012 Floris Bos <bos@je-eigen-domein.nl>
* Copyright (c) 2014 Luc Verhaegen <libv@skynet.be>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>
#include <errno.h>
#include <stdbool.h>
#include "common.h"
typedef uint32_t u32;
/* from u-boot code: */
struct sun4i_dram_para {
u32 baseaddr;
u32 clock;
u32 type;
u32 rank_num;
u32 density;
u32 io_width;
u32 bus_width;
u32 cas;
u32 zq;
u32 odt_en;
u32 size;
u32 tpr0;
u32 tpr1;
u32 tpr2;
u32 tpr3;
u32 tpr4;
u32 tpr5;
u32 emr1;
u32 emr2;
u32 emr3;
};
#define DEVMEM_FILE "/dev/mem"
static int devmem_fd;
enum sunxi_soc_version {
SUNXI_SOC_SUN4I = 0x1623, /* A10 */
SUNXI_SOC_SUN5I = 0x1625, /* A13, A10s */
SUNXI_SOC_SUN6I = 0x1633, /* A31 */
SUNXI_SOC_SUN7I = 0x1651, /* A20 */
SUNXI_SOC_SUN8I = 0x1650, /* A23 */
SUNXI_SOC_SUN9I = 0x1667, /* A33 */
SUNXI_SOC_SUN10I = 0x1635, /* A80 */
SUNXI_SOC_H3 = 0x1680, /* H3 */
};
static enum sunxi_soc_version soc_version;
/*
* Libv's favourite register handling calls.
*/
unsigned int
sunxi_io_read(void *base, int offset)
{
return *(volatile unsigned int*) (base + offset);
}
void
sunxi_io_write(void *base, int offset, unsigned int value)
{
*(volatile unsigned int*) (base + offset) = value;
}
void
sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask)
{
unsigned int tmp = sunxi_io_read(base, offset);
tmp &= ~mask;
tmp |= value & mask;
sunxi_io_write(base, offset, tmp);
}
/*
* Find out exactly which SoC we are dealing with.
*/
#define SUNXI_IO_SRAM_BASE 0x01C00000
#define SUNXI_IO_SRAM_SIZE 0x00001000
#define SUNXI_IO_SRAM_VERSION 0x24
static int
soc_version_read(void)
{
void *base;
unsigned int restore;
base = mmap(NULL, SUNXI_IO_SRAM_SIZE, PROT_READ|PROT_WRITE,
MAP_SHARED, devmem_fd, SUNXI_IO_SRAM_BASE);
if (base == MAP_FAILED) {
fprintf(stderr, "Failed to map sram registers: %s\n",
strerror(errno));
return errno;
}
restore = sunxi_io_read(base, SUNXI_IO_SRAM_VERSION);
sunxi_io_mask(base, SUNXI_IO_SRAM_VERSION, 0x8000, 0x8000);
soc_version = sunxi_io_read(base, SUNXI_IO_SRAM_VERSION) >> 16;
sunxi_io_mask(base, SUNXI_IO_SRAM_VERSION, restore, 0x8000);
munmap(base, SUNXI_IO_SRAM_SIZE);
return 0;
}
/*
* Read DRAM clock.
*/
#define SUNXI_IO_CCM_BASE 0x01C20000
#define SUNXI_IO_CCM_SIZE 0x00001000
#define SUNXI_IO_CCM_PLL5_CFG 0x20
static int
sunxi_dram_clock_read(unsigned int *clock)
{
void *base;
unsigned int tmp;
int n, k, m;
base = mmap(NULL, SUNXI_IO_CCM_SIZE, PROT_READ,
MAP_SHARED, devmem_fd, SUNXI_IO_CCM_BASE);
if (base == MAP_FAILED) {
fprintf(stderr, "Failed to map ccm registers: %s\n",
strerror(errno));
return errno;
}
tmp = sunxi_io_read(base, SUNXI_IO_CCM_PLL5_CFG);
munmap(base, SUNXI_IO_CCM_SIZE);
n = (tmp >> 8) & 0x1F;
k = ((tmp >> 4) & 0x03) + 1;
m = (tmp & 0x03) + 1;
switch (soc_version) {
case SUNXI_SOC_SUN6I:
case SUNXI_SOC_SUN8I:
n++;
break;
default:
break;
}
*clock = (24 * n * k) / m;
return 0;
}
struct regs {
int offset;
char *name;
};
static int
dram_registers_print(unsigned int address, int size, const struct regs *regs,
const char *description, const char *prefix)
{
void *base;
int i, j;
base = mmap(NULL, size, PROT_READ, MAP_SHARED, devmem_fd, address);
if (base == MAP_FAILED) {
fprintf(stderr, "Failed to map %s registers: %s\n",
description, strerror(errno));
return errno;
}
printf("/*\n");
printf(" * %s Registers\n", description);
printf(" */\n");
for (i = 0; i < size; i += 4) {
unsigned int reg = sunxi_io_read(base, i);
for (j = 0; regs[j].name; j++)
if (i == regs[j].offset) {
printf("%s = 0x%08x;\n", regs[j].name, reg);
}
if (reg && !regs[j].name)
printf("%s_%03X = 0x%08x;\n", prefix, i, reg);
}
printf("\n");
munmap(base, size);
return 0;
}
static int
dram_register_range_print(unsigned int address, int size,
const char *description, const char *prefix)
{
void *base;
int i;
base = mmap(NULL, size, PROT_READ, MAP_SHARED, devmem_fd, address);
if (base == MAP_FAILED) {
fprintf(stderr, "Failed to map %s registers: %s\n",
description, strerror(errno));
return errno;
}
printf("/*\n");
printf(" * %s Registers\n", description);
printf(" */\n");
for (i = 0; i < size; i += 4) {
unsigned int reg = sunxi_io_read(base, i);
if (reg)
printf("%s_%03X = 0x%08x;\n", prefix, i, reg);
}
printf("\n");
munmap(base, size);
return 0;
}
/*
* Read DRAM parameters.
*/
#define SUN4I_IO_DRAM_BASE 0x01C01000
#define SUN4I_IO_DRAM_SIZE 0x00001000
#define SUN4I_IO_DRAM_CCR 0x000 /* controller configuration register */
#define SUN4I_IO_DRAM_DCR 0x004 /* dram configuration */
#define SUN4I_IO_DRAM_IOCR 0x008 /* i/o configuration */
#define SUN4I_IO_DRAM_TPR0 0x014 /* dram timing parameters register 0 */
#define SUN4I_IO_DRAM_TPR1 0x018 /* dram timing parameters register 1 */
#define SUN4I_IO_DRAM_TPR2 0x01C /* dram timing parameters register 2 */
#define SUN4I_IO_DRAM_ZQCR0 0x0A8 /* zq control register 0 */
#define SUN4I_IO_DRAM_ZQCR1 0x0AC /* zq control register 1 */
#define SUN4I_IO_DRAM_MR 0x1F0 /* mode register */
#define SUN4I_IO_DRAM_EMR 0x1F4 /* extended mode register */
#define SUN4I_IO_DRAM_EMR2 0x1F8 /* extended mode register */
#define SUN4I_IO_DRAM_EMR3 0x1FC /* extended mode register */
#define SUN4I_IO_DRAM_DLLCR0 0x204 /* dll control register 0(byte 0) */
#define SUN4I_IO_DRAM_DLLCR1 0x208 /* dll control register 1(byte 1) */
#define SUN4I_IO_DRAM_DLLCR2 0x20C /* dll control register 2(byte 2) */
#define SUN4I_IO_DRAM_DLLCR3 0x210 /* dll control register 3(byte 3) */
#define SUN4I_IO_DRAM_DLLCR4 0x214 /* dll control register 4(byte 4) */
static int
sun4i_dram_parameters_read(struct sun4i_dram_para *dram_para)
{
void *base;
unsigned int zqcr0, dcr;
unsigned int dllcr0, dllcr1, dllcr2, dllcr3, dllcr4;
base = mmap(NULL, SUN4I_IO_DRAM_SIZE, PROT_READ,
MAP_SHARED, devmem_fd, SUN4I_IO_DRAM_BASE);
if (base == MAP_FAILED) {
fprintf(stderr, "Failed to map dram registers: %s\n",
strerror(errno));
return errno;
}
dram_para->tpr0 = sunxi_io_read(base, SUN4I_IO_DRAM_TPR0);
dram_para->tpr1 = sunxi_io_read(base, SUN4I_IO_DRAM_TPR1);
dram_para->tpr2 = sunxi_io_read(base, SUN4I_IO_DRAM_TPR2);
dllcr0 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR0) >> 6) & 0x3F;
dllcr1 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR1) >> 14) & 0x0F;
dllcr2 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR2) >> 14) & 0x0F;
dllcr3 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR3) >> 14) & 0x0F;
dllcr4 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR4) >> 14) & 0x0F;
dram_para->tpr3 = (dllcr0 << 16) |
(dllcr4 << 12) | (dllcr3 << 8) | (dllcr2 << 4) | dllcr1;
if (soc_version == SUNXI_SOC_SUN7I) {
if (sunxi_io_read(base, SUN4I_IO_DRAM_CCR) & 0x20)
dram_para->tpr4 |= 0x01;
if (!(sunxi_io_read(base, SUN4I_IO_DRAM_ZQCR1) & 0x01000000))
dram_para->tpr4 |= 0x02;
}
dram_para->cas = (sunxi_io_read(base, SUN4I_IO_DRAM_MR) >> 4) & 0x0F;
dram_para->emr1 = sunxi_io_read(base, SUN4I_IO_DRAM_EMR);
dram_para->emr2 = sunxi_io_read(base, SUN4I_IO_DRAM_EMR2);
dram_para->emr3 = sunxi_io_read(base, SUN4I_IO_DRAM_EMR3);
dram_para->odt_en = sunxi_io_read(base, SUN4I_IO_DRAM_IOCR) & 0x03;
zqcr0 = sunxi_io_read(base, SUN4I_IO_DRAM_ZQCR0);
dram_para->zq = (zqcr0 & 0xf0000000) |
((zqcr0 >> 20) & 0xff) |
((zqcr0 & 0xfffff) << 8);
dcr = sunxi_io_read(base, SUN4I_IO_DRAM_DCR);
if (dcr & 0x01) {
dram_para->cas += 4;
dram_para->type = 3;
} else
dram_para->type = 2;
dram_para->density = (1 << ((dcr >> 3) & 0x07)) * 256;
dram_para->rank_num = ((dcr >> 10) & 0x03) + 1;
dram_para->io_width = ((dcr >> 1) & 0x03) * 8;
dram_para->bus_width = (((dcr >> 6) & 3) + 1) * 8;
munmap(base, SUN4I_IO_DRAM_SIZE);
return 0;
}
/*
* Print a dram.c that can be stuck immediately into u-boot.
*/
void
sun4i_dram_para_print_uboot(struct sun4i_dram_para *dram_para)
{
printf("// place this file in board/sunxi/ in u-boot\n");
printf("/* this file is generated, don't edit it yourself */\n");
printf("\n");
printf("#include \"common.h\"\n");
printf("#include <asm/arch/dram.h>\n");
printf("\n");
printf("static struct dram_para dram_para = {\n");
printf("\t.clock = %d,\n", dram_para->clock);
printf("\t.type = %d,\n", dram_para->type);
printf("\t.rank_num = %d,\n", dram_para->rank_num);
printf("\t.density = %d,\n", dram_para->density);
printf("\t.io_width = %d,\n", dram_para->io_width);
printf("\t.bus_width = %d,\n", dram_para->bus_width);
printf("\t.cas = %d,\n", dram_para->cas);
printf("\t.zq = 0x%02x,\n", dram_para->zq);
printf("\t.odt_en = %d,\n", dram_para->odt_en);
printf("\t.size = !!! FIXME !!!, /* in MiB */\n");
printf("\t.tpr0 = 0x%08x,\n", dram_para->tpr0);
printf("\t.tpr1 = 0x%04x,\n", dram_para->tpr1);
printf("\t.tpr2 = 0x%05x,\n", dram_para->tpr2);
printf("\t.tpr3 = 0x%02x,\n", dram_para->tpr3);
printf("\t.tpr4 = 0x%02x,\n", dram_para->tpr4);
printf("\t.tpr5 = 0x%02x,\n", dram_para->tpr5);
printf("\t.emr1 = 0x%02x,\n", dram_para->emr1);
printf("\t.emr2 = 0x%02x,\n", dram_para->emr2);
printf("\t.emr3 = 0x%02x,\n", dram_para->emr3);
printf("};\n");
printf("\n");
printf("unsigned long sunxi_dram_init(void)\n");
printf("{\n");
printf("\treturn dramc_init(&dram_para);\n");
printf("}\n");
}
/*
* Print output matching the .fex output, so it can be stuck in a
* fex file directly.
*/
void
sun4i_dram_para_print_fex(struct sun4i_dram_para *dram_para)
{
printf("; Insert this section into your .fex file\n");
printf("[dram_para]\n");
printf("dram_baseaddr = 0x40000000\n");
printf("dram_clk = %d\n", dram_para->clock);
printf("dram_type = %d\n", dram_para->type);
printf("dram_rank_num = %d\n", dram_para->rank_num);
printf("dram_chip_density = %d\n", dram_para->density);
printf("dram_io_width = %d\n", dram_para->io_width);
printf("dram_bus_width = %d\n", dram_para->bus_width);
printf("dram_cas = %d\n", dram_para->cas);
printf("dram_zq = 0x%02x\n", dram_para->zq);
printf("dram_odt_en = %d\n", dram_para->odt_en);
printf("dram_size = !!! FIXME !!!\n");
printf("dram_tpr0 = 0x%08x\n", dram_para->tpr0);
printf("dram_tpr1 = 0x%04x\n", dram_para->tpr1);
printf("dram_tpr2 = 0x%05x\n", dram_para->tpr2);
printf("dram_tpr3 = 0x%02x\n", dram_para->tpr3);
printf("dram_tpr4 = 0x%02x\n", dram_para->tpr4);
printf("dram_tpr5 = 0x%02x\n", dram_para->tpr5);
printf("dram_emr1 = 0x%02x\n", dram_para->emr1);
printf("dram_emr2 = 0x%02x\n", dram_para->emr2);
printf("dram_emr3 = 0x%02x\n", dram_para->emr3);
}
static int
sun4i_dram_para_print(bool uboot)
{
struct sun4i_dram_para dram_para = { .baseaddr = 0 };
int ret;
ret = sunxi_dram_clock_read(&dram_para.clock);
if (ret)
return ret;
ret = sun4i_dram_parameters_read(&dram_para);
if (ret)
return ret;
if (uboot)
sun4i_dram_para_print_uboot(&dram_para);
else
sun4i_dram_para_print_fex(&dram_para);
return 0;
}
/*
*
*/
#define SUN6I_IO_DRAMCOM_BASE 0x01C62000
#define SUN6I_IO_DRAMCOM_SIZE 0x0300
#define SUN6I_IO_DRAMCTL_BASE 0x01C63000
#define SUN6I_IO_DRAMCTL_SIZE 0x0400
#define SUN6I_IO_DRAMPHY_BASE 0x01C65000
#define SUN6I_IO_DRAMPHY_SIZE 0x0400
static struct regs
sun6i_dramcom_regs[] = {
{0x00, "SDR_COM_CR"},
{0x04, "SDR_COM_CCR"},
{0x10, "SDR_COM_MFACR"},
{0x30, "SDR_COM_MSACR"},
{0x50, "SDR_COM_MBACR"},
{0, NULL}
};
static struct regs
sun6i_dramctl_regs[] = {
{0x004, "SDR_SCTL"},
{0x008, "SDR_SSTAT"},
{0x040, "SDR_MCMD"},
{0x04c, "SDR_CMDSTAT"},
{0x050, "SDR_CMDSTATEN"},
{0x060, "SDR_MRRCFG0"},
{0x064, "SDR_MRRSTAT0"},
{0x068, "SDR_MRRSTAT1"},
{0x07c, "SDR_MCFG1"},
{0x080, "SDR_MCFG"},
{0x084, "SDR_PPCFG"},
{0x088, "SDR_MSTAT"},
{0x08c, "SDR_LP2ZQCFG"},
{0x094, "SDR_DTUSTAT"},
{0x098, "SDR_DTUNA"},
{0x09c, "SDR_DTUNE"},
{0x0a0, "SDR_DTUPRD0"},
{0x0a4, "SDR_DTUPRD1"},
{0x0a8, "SDR_DTUPRD2"},
{0x0ac, "SDR_DTUPRD3"},
{0x0b0, "SDR_DTUAWDT"},
{0x0c0, "SDR_TOGCNT1U"},
{0x0cc, "SDR_TOGCNT100N"},
{0x0d0, "SDR_TREFI"},
{0x0d4, "SDR_TMRD"},
{0x0d8, "SDR_TRFC"},
{0x0dc, "SDR_TRP"},
{0x0e0, "SDR_TRTW"},
{0x0e4, "SDR_TAL"},
{0x0e8, "SDR_TCL"},
{0x0ec, "SDR_TCWL"},
{0x0f0, "SDR_TRAS"},
{0x0f4, "SDR_TRC"},
{0x0f8, "SDR_TRCD"},
{0x0fc, "SDR_TRRD"},
{0x100, "SDR_TRTP"},
{0x104, "SDR_TWR"},
{0x108, "SDR_TWTR"},
{0x10c, "SDR_TEXSR"},
{0x110, "SDR_TXP"},
{0x114, "SDR_TXPDLL"},
{0x118, "SDR_TZQCS"},
{0x11c, "SDR_TZQCSI"},
{0x120, "SDR_TDQS"},
{0x124, "SDR_TCKSRE"},
{0x128, "SDR_TCKSRX"},
{0x12c, "SDR_TCKE"},
{0x130, "SDR_TMOD"},
{0x134, "SDR_TRSTL"},
{0x138, "SDR_TZQCL"},
{0x13c, "SDR_TMRR"},
{0x140, "SDR_TCKESR"},
{0x144, "SDR_TDPD"},
{0x200, "SDR_DTUWACTL"},
{0x204, "SDR_DTURACTL"},
{0x208, "SDR_DTUCFG"},
{0x20c, "SDR_DTUECTL"},
{0x210, "SDR_DTUWD0"},
{0x214, "SDR_DTUWD1"},
{0x218, "SDR_DTUWD2"},
{0x21c, "SDR_DTUWD3"},
{0x220, "SDR_DTUWDM"},
{0x224, "SDR_DTURD0"},
{0x224, "SDR_DTURD1"},
{0x22c, "SDR_DTURD2"},
{0x230, "SDR_DTURD3"},
{0x234, "SDR_DTULFSRWD"},
{0x238, "SDR_DTULFSRRD"},
{0x23c, "SDR_DTUEAF"},
{0x240, "SDR_DFITCTLDLY"},
{0x244, "SDR_DFIODTCFG"},
{0x248, "SDR_DFIODTCFG1"},
{0x24c, "SDR_DFIODTRMAP"},
{0x250, "SDR_DFITPHYWRD"},
{0x254, "SDR_DFITPHYWRL"},
{0x260, "SDR_DFITRDDEN"},
{0x264, "SDR_DFITPHYRDL"},
{0x270, "SDR_DFITPHYUPDTYPE0"},
{0x274, "SDR_DFITPHYUPDTYPE1"},
{0x278, "SDR_DFITPHYUPDTYPE2"},
{0x27c, "SDR_DFITPHYUPDTYPE3"},
{0x280, "SDR_DFITCTRLUPDMIN"},
{0x284, "SDR_DFITCTRLUPDMAX"},
{0x288, "SDR_DFITCTRLUPDDLY"},
{0x290, "SDR_DFIUPDCFG"},
{0x294, "SDR_DFITREFMSKI"},
{0x298, "SDR_DFITCRLUPDI"},
{0x2ac, "SDR_DFITRCFG0"},
{0x2b0, "SDR_DFITRSTAT0"},
{0x2b4, "SDR_DFITRWRLVLEN"},
{0x2b8, "SDR_DFITRRDLVLEN"},
{0x2bc, "SDR_DFITRRDLVLGATEEN"},
{0x2c4, "SDR_DFISTCFG0"},
{0x2c8, "SDR_DFISTCFG1"},
{0x2d0, "SDR_DFITDRAMCLKEN"},
{0x2d4, "SDR_DFITDRAMCLKDIS"},
{0x2f0, "SDR_DFILPCFG0"},
{0, NULL}
};
static struct regs
sun6i_dramphy_regs[] = {
{0x004, "SDR_PIR"},
{0x008, "SDR_PGCR"},
{0x00c, "SDR_PGSR"},
{0x010, "SDR_DLLGCR"},
{0x014, "SDR_ACDLLCR"},
{0x018, "SDR_PTR0"},
{0x01c, "SDR_PTR1"},
{0x020, "SDR_PTR2"},
{0x024, "SDR_ACIOCR"},
{0x028, "SDR_DXCCR"},
{0x02c, "SDR_DSGCR"},
{0x030, "SDR_DCR"},
{0x034, "SDR_DTPR0"},
{0x038, "SDR_DTPR1"},
{0x03c, "SDR_DTPR2"},
{0x040, "SDR_MR0"},
{0x044, "SDR_MR1"},
{0x048, "SDR_MR2"},
{0x04c, "SDR_MR3"},
{0x050, "SDR_ODTCR"},
{0x054, "SDR_DTAR"},
{0x058, "SDR_DTDT0"},
{0x05c, "SDR_DTDT1"},
{0x0c0, "SDR_DCUAR"},
{0x0c4, "SDR_DCUDR"},
{0x0c8, "SDR_DCURR"},
{0x0cc, "SDR_DCULR"},
{0x0d0, "SDR_DCUGCR"},
{0x0d4, "SDR_DCUTPR"},
{0x0d8, "SDR_DCUSR0"},
{0x0dc, "SDR_DCUSR1"},
{0x100, "SDR_BISTRR"},
{0x104, "SDR_BISTMSKR0"},
{0x108, "SDR_BISTMSKR1"},
{0x10c, "SDR_BISTWCR"},
{0x110, "SDR_BISTLSR"},
{0x114, "SDR_BISTAR0"},
{0x118, "SDR_BISTAR1"},
{0x11c, "SDR_BISTAR2"},
{0x120, "SDR_BISTUDPR"},
{0x124, "SDR_BISTGSR"},
{0x128, "SDR_BISTWER"},
{0x12c, "SDR_BISTBER0"},
{0x130, "SDR_BISTBER1"},
{0x134, "SDR_BISTBER2"},
{0x138, "SDR_BISTWCSR"},
{0x13c, "SDR_BISTFWR0"},
{0x140, "SDR_BISTFWR1"},
{0x180, "SDR_ZQ0CR0"},
{0x184, "SDR_ZQ0CR1"},
{0x188, "SDR_ZQ0SR0"},
{0x18c, "SDR_ZQ0SR1"},
{0x1c0, "SDR_DX0GCR"},
{0x1c4, "SDR_DX0GSR0"},
{0x1c8, "SDR_DX0GSR1"},
{0x1cc, "SDR_DX0DLLCR"},
{0x1d0, "SDR_DX0DQTR"},
{0x1d4, "SDR_DX0DQSTR"},
{0x200, "SDR_DX1GCR"},
{0x204, "SDR_DX1GSR0"},
{0x208, "SDR_DX1GSR1"},
{0x20c, "SDR_DX1DLLCR"},
{0x210, "SDR_DX1DQTR"},
{0x214, "SDR_DX1DQSTR"},
{0x240, "SDR_DX2GCR"},
{0x244, "SDR_DX2GSR0"},
{0x248, "SDR_DX2GSR1"},
{0x24c, "SDR_DX2DLLCR"},
{0x250, "SDR_DX2DQTR"},
{0x254, "SDR_DX2DQSTR"},
{0x280, "SDR_DX3GCR"},
{0x284, "SDR_DX3GSR0"},
{0x288, "SDR_DX3GSR1"},
{0x28c, "SDR_DX3DLLCR"},
{0x290, "SDR_DX3DQTR"},
{0x294, "SDR_DX3DQSTR"},
{0, NULL}
};
static int
sun6i_dram_regs_print(void)
{
unsigned int clock;
int ret;
ret = sunxi_dram_clock_read(&clock);
if (ret)
return ret;
printf("DRAM Clock: %dMHz\n", clock);
ret = dram_registers_print(SUN6I_IO_DRAMCOM_BASE,
SUN6I_IO_DRAMCOM_SIZE,
&sun6i_dramcom_regs[0],
"DRAM COM", "SDR_COM");
if (ret)
return ret;
ret = dram_registers_print(SUN6I_IO_DRAMCTL_BASE,
SUN6I_IO_DRAMCTL_SIZE,
&sun6i_dramctl_regs[0],
"DRAM CTL", "SDR_CTL");
if (ret)
return ret;
ret = dram_registers_print(SUN6I_IO_DRAMPHY_BASE,
SUN6I_IO_DRAMPHY_SIZE,
&sun6i_dramphy_regs[0],
"DRAM PHY", "SDR_PHY");
if (ret)
return ret;
return 0;
}
/*
*
*/
static int
sun8i_dram_regs_print(void)
{
unsigned int clock;
int ret;
ret = sunxi_dram_clock_read(&clock);
if (ret)
return ret;
printf("DRAM Clock: %dMHz\n", clock);
ret = dram_register_range_print(SUN6I_IO_DRAMCOM_BASE,
SUN6I_IO_DRAMCOM_SIZE,
"DRAM COM", "SDR_COM");
if (ret)
return ret;
ret = dram_register_range_print(SUN6I_IO_DRAMCTL_BASE,
SUN6I_IO_DRAMCTL_SIZE,
"DRAM CTL", "SDR_CTL");
if (ret)
return ret;
ret = dram_register_range_print(SUN6I_IO_DRAMPHY_BASE,
SUN6I_IO_DRAMPHY_SIZE,
"DRAM PHY", "SDR_PHY");
if (ret)
return ret;
return 0;
}
static void
print_usage(const char *name)
{
puts("sunxi-meminfo " VERSION "\n");
printf("Utility to retrieve DRAM information from registers on "
"Allwinner SoCs.\n");
printf("\n");
printf("This is part of the sunxi-tools package from the sunxi "
"project. ");
printf("For more \ninformation visit "
"http://linux-sunxi.org/Sunxi-tools.\n");
printf("\n");
printf("Usage: %s [OPTION]\n", name);
printf("\n");
printf("Options:\n");
printf(" -f: print in FEX format (default).\n");
printf(" -u: print in sunxi U-Boot dram.c file format.\n");
printf(" -h: print this usage information.\n");
}
int
main(int argc, char *argv[])
{
bool uboot;
int ret;
if (argc == 2) {
if (argv[1][0] == '-') {
if (argv[1][1] == 'f')
uboot = false;
else if (argv[1][1] == 'u')
uboot = true;
else if (argv[1][1] == 'h')
goto help;
else if ((argv[1][1] == '-') && (argv[1][2] == 'h'))
goto help;
else
goto usage;
if (argv[1][2] != 0)
goto usage;
} else
goto usage;
} else if (argc == 1)
uboot = false;
else
goto usage;
devmem_fd = open(DEVMEM_FILE, O_RDWR);
if (devmem_fd == -1) {
fprintf(stderr, "Error: failed to open %s: %s\n", DEVMEM_FILE,
strerror(errno));
return errno;
}
ret = soc_version_read();
if (ret)
return ret;
switch (soc_version) {
case SUNXI_SOC_SUN4I:
case SUNXI_SOC_SUN5I:
case SUNXI_SOC_SUN7I:
return sun4i_dram_para_print(uboot);
case SUNXI_SOC_SUN6I:
return sun6i_dram_regs_print();
case SUNXI_SOC_SUN8I:
case SUNXI_SOC_H3:
return sun8i_dram_regs_print();
default:
fprintf(stderr, "Error: unknown or unhandled Soc: 0x%04X\n",
soc_version);
return -1;
}
usage:
fprintf(stderr, "Error: wrong argument(s).\n");
print_usage(argv[0]);
return EINVAL;
help:
print_usage(argv[0]);
return 0;
}

View File

@ -1489,8 +1489,8 @@ int main(int argc, char* argv[])
// Wait until BSY is released as there is a possibility for the
// initiator to assert it while setting the ID (for up to 3 seconds)
if (bus->GetBSY()) {
int now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
int now = SysTimer::instance()->GetTimerLow();
while ((SysTimer::instance()->GetTimerLow() - now) < 3 * 1000 * 1000) {
bus->Acquire();
if (!bus->GetBSY()) {
break;

View File

@ -212,8 +212,8 @@ bool WaitPhase(BUS::phase_t phase)
DWORD now;
// Timeout (3000ms)
now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
now = SysTimer::instance()->GetTimerLow();
while ((SysTimer::instance()->GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Acquire();
if (bus.GetREQ() && bus.GetPhase() == phase) {
return true;

BIN
src/raspberrypi/registers Executable file

Binary file not shown.

406
src/raspberrypi/registers.c Normal file
View File

@ -0,0 +1,406 @@
// Kernel module to access cycle count registers:
// https://matthewarcus.wordpress.com/2018/01/27/using-the-cycle-counter-registers-on-the-raspberry-pi-3/
//https://mindplusplus.wordpress.com/2013/05/21/accessing-the-raspberry-pis-1mhz-timer/
// Reading register from user space:
// https://stackoverflow.com/questions/59749160/reading-from-register-of-allwinner-h3-arm-processor
// Maybe kernel patch>
//https://yhbt.net/lore/all/20140707085858.GG16262@lukather/T/
//
// Access the Raspberry Pi System Timer registers directly.
//
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
#include "common.h"
typedef uint32_t u32;
/* from u-boot code: */
struct sun4i_dram_para {
u32 baseaddr;
u32 clock;
u32 type;
u32 rank_num;
u32 density;
u32 io_width;
u32 bus_width;
u32 cas;
u32 zq;
u32 odt_en;
u32 size;
u32 tpr0;
u32 tpr1;
u32 tpr2;
u32 tpr3;
u32 tpr4;
u32 tpr5;
u32 emr1;
u32 emr2;
u32 emr3;
};
#define DEVMEM_FILE "/dev/mem"
static int devmem_fd;
enum sunxi_soc_version {
SUNXI_SOC_SUN4I = 0x1623, /* A10 */
SUNXI_SOC_SUN5I = 0x1625, /* A13, A10s */
SUNXI_SOC_SUN6I = 0x1633, /* A31 */
SUNXI_SOC_SUN7I = 0x1651, /* A20 */
SUNXI_SOC_SUN8I = 0x1650, /* A23 */
SUNXI_SOC_SUN9I = 0x1667, /* A33 */
SUNXI_SOC_SUN10I = 0x1635, /* A80 */
SUNXI_SOC_H3 = 0x1680, /* H3 */
};
static enum sunxi_soc_version soc_version;
// #define PERIPHERAL_BASE 0x20000000 // For Pi 1 and 2
//#define PERIPHERAL_BASE 0x3F000000 // For Pi 3
#define PERIPHERAL_BASE 0xfe000000 // For PI 4
#define SYSTEM_TIMER_OFFSET 0x3000
volatile void* hs_timer;
volatile void* system_bus;
static const uint32_t system_bus_base_address = 0x01C20000;
static const uint32_t BUS_CLK_GATING_REG0 = 0x60;
static const uint32_t BUS_CLK_GATING_REG1 = 0x64;
static const uint32_t BUS_CLK_GATING_REG2 = 0x68;
static const uint32_t BUS_CLK_GATING_REG3 = 0x6C;
static const uint32_t BUS_CLK_GATING_REG4 = 0x70;
static const uint32_t BUS_CLK_GATING_REG0_USBOHCI3 =31;
static const uint32_t BUS_CLK_GATING_REG0_USBOHCI2 =30;
static const uint32_t BUS_CLK_GATING_REG0_USBOHCI1 =29;
static const uint32_t BUS_CLK_GATING_REG0_USBOHCI0 =28;
static const uint32_t BUS_CLK_GATING_REG0_USBEHCI3 =27;
static const uint32_t BUS_CLK_GATING_REG0_USBEHCI2 =26;
static const uint32_t BUS_CLK_GATING_REG0_USBEHCI1 =25;
static const uint32_t BUS_CLK_GATING_REG0_USBEHCI0 =24;
static const uint32_t BUS_CLK_GATING_REG0_USB_OTG =23;
static const uint32_t BUS_CLK_GATING_REG0_SPI1 =21;
static const uint32_t BUS_CLK_GATING_REG0_SPI0 =20;
static const uint32_t BUS_CLK_GATING_REG0_HSTMR =19;
static const uint32_t BUS_CLK_GATING_REG0_TS =18;
static const uint32_t BUS_CLK_GATING_REG0_EMAC =17;
static const uint32_t BUS_CLK_GATING_REG0_DRAM =14;
static const uint32_t BUS_CLK_GATING_REG0_NAND =13;
static const uint32_t BUS_CLK_GATING_REG0_MMC2 =10;
static const uint32_t BUS_CLK_GATING_REG0_MMC1 =9;
static const uint32_t BUS_CLK_GATING_REG0_MMC0 =8;
static const uint32_t BUS_CLK_GATING_REG0_DMA =6;
static const uint32_t BUS_CLK_GATING_REG0_CE =5;
static const uint32_t BUS_SOFT_RST_REG0 = 0x2C0;
static const uint32_t BUS_SOFT_RST_REG1 = 0x2C4;
static const uint32_t BUS_SOFT_RST_REG2 = 0x2C8;
static const uint32_t BUS_SOFT_RST_REG3 = 0x2D0;
static const uint32_t BUS_SOFT_RST_REG4 = 0x2D8;
static const uint32_t BUS_SOFT_RST_REG0_USBOHCI3 =31;
static const uint32_t BUS_SOFT_RST_REG0_USBOHCI2 =30;
static const uint32_t BUS_SOFT_RST_REG0_USBOHCI1 =29;
static const uint32_t BUS_SOFT_RST_REG0_USBOHCI0 =28;
static const uint32_t BUS_SOFT_RST_REG0_USBEHCI3 =27;
static const uint32_t BUS_SOFT_RST_REG0_USBEHCI2 =26;
static const uint32_t BUS_SOFT_RST_REG0_USBEHCI1 =25;
static const uint32_t BUS_SOFT_RST_REG0_USBEHCI0 =24;
static const uint32_t BUS_SOFT_RST_REG0_USB_OTG =23;
static const uint32_t BUS_SOFT_RST_REG0_SPI1 =21;
static const uint32_t BUS_SOFT_RST_REG0_SPI0 =20;
static const uint32_t BUS_SOFT_RST_REG0_HSTMR =19;
static const uint32_t BUS_SOFT_RST_REG0_TS =18;
static const uint32_t BUS_SOFT_RST_REG0_EMAC =17;
static const uint32_t BUS_SOFT_RST_REG0_DRAM =14;
static const uint32_t BUS_SOFT_RST_REG0_NAND =13;
static const uint32_t BUS_SOFT_RST_REG0_MMC2 =10;
static const uint32_t BUS_SOFT_RST_REG0_MMC1 =9;
static const uint32_t BUS_SOFT_RST_REG0_MMC0 =8;
static const uint32_t BUS_SOFT_RST_REG0_DMA =6;
static const uint32_t BUS_SOFT_RST_REG0_CE =5;
/*
* Find out exactly which SoC we are dealing with.
*/
#define SUNXI_IO_SRAM_BASE 0x01C00000
#define SUNXI_IO_SRAM_SIZE 0x00001000
#define SUNXI_IO_SRAM_VERSION 0x24
static const uint32_t hs_timer_base_address = 0x01C60000;
static const uint32_t HS_TMR_IRA_EN_EG = 0x00;
static const uint32_t HS_TMR_IRQ_STAT_REG = 0x04;
static const uint32_t HS_TMR_CTRL_REG = 0x10;
static const uint32_t HS_TMR_INTV_LO_REG = 0x14;
static const uint32_t HS_TMR_INTV_HI_REG = 0x18;
static const uint32_t HS_TMR_CURNT_LO_REG = 0x1C;
static const uint32_t HS_TMR_CURNT_HI_REG = 0x20;
#define ST_BASE (PERIPHERAL_BASE + SYSTEM_TIMER_OFFSET)
// Sytem Timer Registers layout
typedef struct {
uint32_t control_and_status;
uint32_t counter_low;
uint32_t counter_high;
uint32_t compare_0;
uint32_t compare_1;
uint32_t compare_2;
uint32_t compare_3;
} system_timer_t;
inline uint32_t set_bit(uint32_t value, uint32_t bit_num){
return( value | (1 << bit_num));
}
inline uint32_t clear_bit(uint32_t value, uint32_t bit_num){
return( value & ~(1 << bit_num));
}
inline uint32_t get_bit(uint32_t value, uint32_t bit_num){
return ((value >> bit_num) & 1UL);
}
inline uint32_t io_readl(volatile void* base, uint32_t offset){
return *(volatile uint32_t*) ((uint32_t)base + offset);
}
inline void io_writel(volatile void* base, uint32_t offset, uint32_t value){
*(volatile uint32_t*) ((uint32_t)base + offset) = value;
}
void
inline sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask)
{
unsigned int tmp = io_readl(base, offset);
tmp &= ~mask;
tmp |= value & mask;
io_writel(base, offset, tmp);
}
inline uint32_t sysbus_readl(uint32_t offset) { return io_readl(system_bus, offset); }
inline void sysbus_writel(uint32_t offset, uint32_t value){ io_writel(system_bus, offset, value);}
inline uint32_t hstimer_readl(uint32_t offset) { return io_readl(hs_timer, offset); }
inline void hstimer_writel(uint32_t offset, uint32_t value) { io_writel(hs_timer, offset, value);}
void dump_sys_bus(){
printf("System bus..... %08X\n\r", system_bus_base_address);
printf("Gating Reg: %08X %08X %08X %08X %08X\n\r",
sysbus_readl(BUS_CLK_GATING_REG0),
sysbus_readl(BUS_CLK_GATING_REG1),
sysbus_readl(BUS_CLK_GATING_REG2),
sysbus_readl(BUS_CLK_GATING_REG3),
sysbus_readl(BUS_CLK_GATING_REG4)
);
printf("Reset Reg: %08X %08X %08X %08X %08X\n\r",
sysbus_readl(BUS_SOFT_RST_REG0),
sysbus_readl(BUS_SOFT_RST_REG1),
sysbus_readl(BUS_SOFT_RST_REG2),
sysbus_readl(BUS_SOFT_RST_REG3),
sysbus_readl(BUS_SOFT_RST_REG4)
);
}
void dump_hs_timer(){
printf("Hs timer..... %08X\n\r", hs_timer_base_address);
printf("HS_TMR_IRA_EN_EG %08X\n\r", hstimer_readl(HS_TMR_IRA_EN_EG));
printf("HS_TMR_IRQ_STAT_REG %08X\n\r", hstimer_readl(HS_TMR_IRQ_STAT_REG));
printf("HS_TMR_CTRL_REG %08X\n\r", hstimer_readl(HS_TMR_CTRL_REG));
printf("HS_TMR_INTV_LO_REG %08X\n\r", hstimer_readl(HS_TMR_INTV_LO_REG));
printf("HS_TMR_CURNT_LO_REG %08X\n\r", hstimer_readl(HS_TMR_CURNT_LO_REG));
printf("HS_TMR_CURNT_HI_REG %08X\n\r", hstimer_readl(HS_TMR_CURNT_HI_REG));
}
static int
soc_version_read(void)
{
void *base;
unsigned int restore;
base = mmap(NULL, SUNXI_IO_SRAM_SIZE, PROT_READ|PROT_WRITE,
MAP_SHARED, devmem_fd, SUNXI_IO_SRAM_BASE);
if (base == MAP_FAILED) {
fprintf(stderr, "Failed to map sram registers:");
// %s\n",
// strerror(errno));
return -1;
}
restore = io_readl(base, SUNXI_IO_SRAM_VERSION);
sunxi_io_mask(base, SUNXI_IO_SRAM_VERSION, 0x8000, 0x8000);
soc_version = (sunxi_soc_version)(io_readl(base, SUNXI_IO_SRAM_VERSION) >> 16);
sunxi_io_mask(base, SUNXI_IO_SRAM_VERSION, restore, 0x8000);
munmap(base, SUNXI_IO_SRAM_SIZE);
return 0;
}
// Get access to the System Timer registers in user memory space.
void get_hs_timer() {
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
printf("1 can't open /dev/mem \n");
exit(-1);
}
hs_timer = mmap(
NULL,
4096,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
// ST_BASE
hs_timer_base_address
);
system_bus = mmap(
NULL,
4096,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
// ST_BASE
system_bus_base_address
);
close(fd);
if (hs_timer == MAP_FAILED) {
printf("mmap error %d\n", (int)hs_timer); // errno also set!
exit(-1);
}
}
int main(int argc, char **argv) {
devmem_fd = open(DEVMEM_FILE, O_RDWR);
if (devmem_fd == -1) {
fprintf(stderr, "Error: failed to open %s\n", DEVMEM_FILE);
}
(void)soc_version_read();
printf("SoC Version: %08X\n\r", (uint32_t)soc_version);
get_hs_timer();
// uint32_t t0, t1 = 0;
// uint32_t delay = 2;
dump_sys_bus();
// By default, the HSTimer clock gating is masked. When it is necessary to use
// the HSTimer, its clock gating should be opened in BUS Clock Gating Register 0
// and then de-assert the software reset in BUS Software Reset Register 0 on the
// CCU module. If it is not needed to use the HSTimer, both the gating bit and
// the software reset bit should be set 0.
printf("[Before] CLK GATE: %08X SOFT RST: %08X\n\r",
sysbus_readl(BUS_CLK_GATING_REG0),
sysbus_readl(BUS_SOFT_RST_REG0));
sysbus_writel(BUS_CLK_GATING_REG0, set_bit(sysbus_readl(BUS_CLK_GATING_REG0), BUS_CLK_GATING_REG0_HSTMR));
sysbus_writel(BUS_SOFT_RST_REG0, set_bit(sysbus_readl(BUS_SOFT_RST_REG0), BUS_SOFT_RST_REG0_HSTMR));
printf("[After] CLK GATE: %08X SOFT RST: %08X\n\r",
sysbus_readl(BUS_CLK_GATING_REG0),
sysbus_readl(BUS_SOFT_RST_REG0));
// Make a 1us delay using HSTimer for an instance as follow:
// AHB1CLK will be configured as 100MHz and n_mode,
// Single mode and 2 pre-scale will be selected in this instance
// Set interval value Hi 0x0
hstimer_writel(HS_TMR_INTV_HI_REG, 0x0);
// Set interval value Lo 0x32
hstimer_writel(HS_TMR_INTV_LO_REG, 0x32000000);
// Select n_mode,2 prescale, single mode
hstimer_writel(HS_TMR_CTRL_REG, 0x90);
// Set reload bit
hstimer_writel(HS_TMR_CTRL_REG, hstimer_readl(HS_TMR_CTRL_REG)|(1<<1));
// Enable HSTimer
hstimer_writel(HS_TMR_CTRL_REG, hstimer_readl(HS_TMR_CTRL_REG)|(1<<0));
//Wait for HSTimer to generate pending
while (!(hstimer_readl(HS_TMR_IRQ_STAT_REG)&0x1));
// Clear HSTimer pending
hstimer_writel(HS_TMR_IRQ_STAT_REG, 1);
dump_hs_timer();
// while (1) {
// t0 = system_timer->counter_low;
// while((system_timer->counter_low - t0) < delay)
// // usleep(100);
// t1 = system_timer->counter_low;
// printf ("Elaspsed = %d\n", t1 - t0);
// printf ("Conter high = %d\n", system_timer->counter_high);
// t0 = t1;
// sleep(1);
// }
return 0;
}
// int main(int argc, char **argv) {
// volatile system_timer_t* system_timer = get_system_timer();
// int32_t t0, t1;
// while (1) {
// t0 = system_timer->counter_low;
// usleep(100);
// t1 = system_timer->counter_low;
// printf ("Elaspsed = %d\n", t1 - t0);
// printf ("Conter high = %d\n", system_timer->counter_high);
// t0 = t1;
// }
// return 0;
// }

167
src/raspberrypi/registers.d Normal file
View File

@ -0,0 +1,167 @@
registers: registers.c /usr/include/stdc-predef.h /usr/include/stdio.h \
/usr/include/arm-linux-gnueabihf/bits/libc-header-start.h \
/usr/include/features.h /usr/include/features-time64.h \
/usr/include/arm-linux-gnueabihf/bits/wordsize.h \
/usr/include/arm-linux-gnueabihf/bits/timesize.h \
/usr/include/arm-linux-gnueabihf/sys/cdefs.h \
/usr/include/arm-linux-gnueabihf/bits/long-double.h \
/usr/include/arm-linux-gnueabihf/gnu/stubs.h \
/usr/include/arm-linux-gnueabihf/gnu/stubs-hard.h \
/usr/lib/gcc/arm-linux-gnueabihf/11/include/stddef.h \
/usr/lib/gcc/arm-linux-gnueabihf/11/include/stdarg.h \
/usr/include/arm-linux-gnueabihf/bits/types.h \
/usr/include/arm-linux-gnueabihf/bits/typesizes.h \
/usr/include/arm-linux-gnueabihf/bits/time64.h \
/usr/include/arm-linux-gnueabihf/bits/types/__fpos_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/__mbstate_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/__fpos64_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/__FILE.h \
/usr/include/arm-linux-gnueabihf/bits/types/FILE.h \
/usr/include/arm-linux-gnueabihf/bits/types/struct_FILE.h \
/usr/include/arm-linux-gnueabihf/bits/types/cookie_io_functions_t.h \
/usr/include/arm-linux-gnueabihf/bits/stdio_lim.h \
/usr/include/arm-linux-gnueabihf/bits/floatn.h \
/usr/include/arm-linux-gnueabihf/bits/floatn-common.h \
/usr/include/c++/11/stdlib.h /usr/include/c++/11/cstdlib \
/usr/include/arm-linux-gnueabihf/c++/11/bits/c++config.h \
/usr/include/arm-linux-gnueabihf/c++/11/bits/os_defines.h \
/usr/include/arm-linux-gnueabihf/c++/11/bits/cpu_defines.h \
/usr/include/c++/11/pstl/pstl_config.h /usr/include/stdlib.h \
/usr/include/arm-linux-gnueabihf/bits/waitflags.h \
/usr/include/arm-linux-gnueabihf/bits/waitstatus.h \
/usr/include/arm-linux-gnueabihf/bits/types/locale_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/__locale_t.h \
/usr/include/arm-linux-gnueabihf/sys/types.h \
/usr/include/arm-linux-gnueabihf/bits/types/clock_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/clockid_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/time_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/timer_t.h \
/usr/include/arm-linux-gnueabihf/bits/stdint-intn.h \
/usr/include/endian.h /usr/include/arm-linux-gnueabihf/bits/endian.h \
/usr/include/arm-linux-gnueabihf/bits/endianness.h \
/usr/include/arm-linux-gnueabihf/bits/byteswap.h \
/usr/include/arm-linux-gnueabihf/bits/uintn-identity.h \
/usr/include/arm-linux-gnueabihf/sys/select.h \
/usr/include/arm-linux-gnueabihf/bits/select.h \
/usr/include/arm-linux-gnueabihf/bits/types/sigset_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/__sigset_t.h \
/usr/include/arm-linux-gnueabihf/bits/types/struct_timeval.h \
/usr/include/arm-linux-gnueabihf/bits/types/struct_timespec.h \
/usr/include/arm-linux-gnueabihf/bits/pthreadtypes.h \
/usr/include/arm-linux-gnueabihf/bits/thread-shared-types.h \
/usr/include/arm-linux-gnueabihf/bits/pthreadtypes-arch.h \
/usr/include/arm-linux-gnueabihf/bits/atomic_wide_counter.h \
/usr/include/arm-linux-gnueabihf/bits/struct_mutex.h \
/usr/include/arm-linux-gnueabihf/bits/struct_rwlock.h \
/usr/include/alloca.h \
/usr/include/arm-linux-gnueabihf/bits/stdlib-float.h \
/usr/include/c++/11/bits/std_abs.h /usr/include/fcntl.h \
/usr/include/arm-linux-gnueabihf/bits/fcntl.h \
/usr/include/arm-linux-gnueabihf/bits/fcntl-linux.h \
/usr/include/arm-linux-gnueabihf/bits/types/struct_iovec.h \
/usr/include/linux/falloc.h /usr/include/arm-linux-gnueabihf/bits/stat.h \
/usr/include/arm-linux-gnueabihf/bits/struct_stat.h \
/usr/include/arm-linux-gnueabihf/sys/mman.h \
/usr/include/arm-linux-gnueabihf/bits/mman.h \
/usr/include/arm-linux-gnueabihf/bits/mman-map-flags-generic.h \
/usr/include/arm-linux-gnueabihf/bits/mman-linux.h \
/usr/include/arm-linux-gnueabihf/bits/mman-shared.h \
/usr/include/unistd.h /usr/include/arm-linux-gnueabihf/bits/posix_opt.h \
/usr/include/arm-linux-gnueabihf/bits/environments.h \
/usr/include/arm-linux-gnueabihf/bits/confname.h \
/usr/include/arm-linux-gnueabihf/bits/getopt_posix.h \
/usr/include/arm-linux-gnueabihf/bits/getopt_core.h \
/usr/include/arm-linux-gnueabihf/bits/unistd_ext.h \
/usr/include/linux/close_range.h \
/usr/lib/gcc/arm-linux-gnueabihf/11/include/stdint.h \
/usr/include/stdint.h /usr/include/arm-linux-gnueabihf/bits/wchar.h \
/usr/include/arm-linux-gnueabihf/bits/stdint-uintn.h common.h version.h
/usr/include/stdc-predef.h:
/usr/include/stdio.h:
/usr/include/arm-linux-gnueabihf/bits/libc-header-start.h:
/usr/include/features.h:
/usr/include/features-time64.h:
/usr/include/arm-linux-gnueabihf/bits/wordsize.h:
/usr/include/arm-linux-gnueabihf/bits/timesize.h:
/usr/include/arm-linux-gnueabihf/sys/cdefs.h:
/usr/include/arm-linux-gnueabihf/bits/long-double.h:
/usr/include/arm-linux-gnueabihf/gnu/stubs.h:
/usr/include/arm-linux-gnueabihf/gnu/stubs-hard.h:
/usr/lib/gcc/arm-linux-gnueabihf/11/include/stddef.h:
/usr/lib/gcc/arm-linux-gnueabihf/11/include/stdarg.h:
/usr/include/arm-linux-gnueabihf/bits/types.h:
/usr/include/arm-linux-gnueabihf/bits/typesizes.h:
/usr/include/arm-linux-gnueabihf/bits/time64.h:
/usr/include/arm-linux-gnueabihf/bits/types/__fpos_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/__mbstate_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/__fpos64_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/__FILE.h:
/usr/include/arm-linux-gnueabihf/bits/types/FILE.h:
/usr/include/arm-linux-gnueabihf/bits/types/struct_FILE.h:
/usr/include/arm-linux-gnueabihf/bits/types/cookie_io_functions_t.h:
/usr/include/arm-linux-gnueabihf/bits/stdio_lim.h:
/usr/include/arm-linux-gnueabihf/bits/floatn.h:
/usr/include/arm-linux-gnueabihf/bits/floatn-common.h:
/usr/include/c++/11/stdlib.h:
/usr/include/c++/11/cstdlib:
/usr/include/arm-linux-gnueabihf/c++/11/bits/c++config.h:
/usr/include/arm-linux-gnueabihf/c++/11/bits/os_defines.h:
/usr/include/arm-linux-gnueabihf/c++/11/bits/cpu_defines.h:
/usr/include/c++/11/pstl/pstl_config.h:
/usr/include/stdlib.h:
/usr/include/arm-linux-gnueabihf/bits/waitflags.h:
/usr/include/arm-linux-gnueabihf/bits/waitstatus.h:
/usr/include/arm-linux-gnueabihf/bits/types/locale_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/__locale_t.h:
/usr/include/arm-linux-gnueabihf/sys/types.h:
/usr/include/arm-linux-gnueabihf/bits/types/clock_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/clockid_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/time_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/timer_t.h:
/usr/include/arm-linux-gnueabihf/bits/stdint-intn.h:
/usr/include/endian.h:
/usr/include/arm-linux-gnueabihf/bits/endian.h:
/usr/include/arm-linux-gnueabihf/bits/endianness.h:
/usr/include/arm-linux-gnueabihf/bits/byteswap.h:
/usr/include/arm-linux-gnueabihf/bits/uintn-identity.h:
/usr/include/arm-linux-gnueabihf/sys/select.h:
/usr/include/arm-linux-gnueabihf/bits/select.h:
/usr/include/arm-linux-gnueabihf/bits/types/sigset_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/__sigset_t.h:
/usr/include/arm-linux-gnueabihf/bits/types/struct_timeval.h:
/usr/include/arm-linux-gnueabihf/bits/types/struct_timespec.h:
/usr/include/arm-linux-gnueabihf/bits/pthreadtypes.h:
/usr/include/arm-linux-gnueabihf/bits/thread-shared-types.h:
/usr/include/arm-linux-gnueabihf/bits/pthreadtypes-arch.h:
/usr/include/arm-linux-gnueabihf/bits/atomic_wide_counter.h:
/usr/include/arm-linux-gnueabihf/bits/struct_mutex.h:
/usr/include/arm-linux-gnueabihf/bits/struct_rwlock.h:
/usr/include/alloca.h:
/usr/include/arm-linux-gnueabihf/bits/stdlib-float.h:
/usr/include/c++/11/bits/std_abs.h:
/usr/include/fcntl.h:
/usr/include/arm-linux-gnueabihf/bits/fcntl.h:
/usr/include/arm-linux-gnueabihf/bits/fcntl-linux.h:
/usr/include/arm-linux-gnueabihf/bits/types/struct_iovec.h:
/usr/include/linux/falloc.h:
/usr/include/arm-linux-gnueabihf/bits/stat.h:
/usr/include/arm-linux-gnueabihf/bits/struct_stat.h:
/usr/include/arm-linux-gnueabihf/sys/mman.h:
/usr/include/arm-linux-gnueabihf/bits/mman.h:
/usr/include/arm-linux-gnueabihf/bits/mman-map-flags-generic.h:
/usr/include/arm-linux-gnueabihf/bits/mman-linux.h:
/usr/include/arm-linux-gnueabihf/bits/mman-shared.h:
/usr/include/unistd.h:
/usr/include/arm-linux-gnueabihf/bits/posix_opt.h:
/usr/include/arm-linux-gnueabihf/bits/environments.h:
/usr/include/arm-linux-gnueabihf/bits/confname.h:
/usr/include/arm-linux-gnueabihf/bits/getopt_posix.h:
/usr/include/arm-linux-gnueabihf/bits/getopt_core.h:
/usr/include/arm-linux-gnueabihf/bits/unistd_ext.h:
/usr/include/linux/close_range.h:
/usr/lib/gcc/arm-linux-gnueabihf/11/include/stdint.h:
/usr/include/stdint.h:
/usr/include/arm-linux-gnueabihf/bits/wchar.h:
/usr/include/arm-linux-gnueabihf/bits/stdint-uintn.h:
common.h:
version.h:

View File

@ -0,0 +1,106 @@
// Kernel module to access cycle count registers:
// https://matthewarcus.wordpress.com/2018/01/27/using-the-cycle-counter-registers-on-the-raspberry-pi-3/
//https://mindplusplus.wordpress.com/2013/05/21/accessing-the-raspberry-pis-1mhz-timer/
// Reading register from user space:
// https://stackoverflow.com/questions/59749160/reading-from-register-of-allwinner-h3-arm-processor
// Maybe kernel patch>
//https://yhbt.net/lore/all/20140707085858.GG16262@lukather/T/
//
// Access the Raspberry Pi System Timer registers directly.
//
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
// #define PERIPHERAL_BASE 0x20000000 // For Pi 1 and 2
//#define PERIPHERAL_BASE 0x3F000000 // For Pi 3
#define PERIPHERAL_BASE 0xfe000000 // For PI 4
#define SYSTEM_TIMER_OFFSET 0x3000
#define ST_BASE (PERIPHERAL_BASE + SYSTEM_TIMER_OFFSET)
// Sytem Timer Registers layout
typedef struct {
uint32_t control_and_status;
uint32_t counter_low;
uint32_t counter_high;
uint32_t compare_0;
uint32_t compare_1;
uint32_t compare_2;
uint32_t compare_3;
} system_timer_t;
// Get access to the System Timer registers in user memory space.
system_timer_t * get_system_timer() {
void *system_timer;
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
printf("1 can't open /dev/mem \n");
exit(-1);
}
system_timer = mmap(
NULL,
4096,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
ST_BASE
);
close(fd);
if (system_timer == MAP_FAILED) {
printf("mmap error %d\n", (int)system_timer); // errno also set!
exit(-1);
}
return (system_timer_t*)system_timer;
}
int main(int argc, char **argv) {
volatile system_timer_t* system_timer = get_system_timer();
uint32_t t0, t1 = 0;
uint32_t delay = 2;
while (1) {
t0 = system_timer->counter_low;
while((system_timer->counter_low - t0) < delay)
// usleep(100);
t1 = system_timer->counter_low;
printf ("Elaspsed = %d\n", t1 - t0);
printf ("Conter high = %d\n", system_timer->counter_high);
t0 = t1;
sleep(1);
}
return 0;
}
// int main(int argc, char **argv) {
// volatile system_timer_t* system_timer = get_system_timer();
// int32_t t0, t1;
// while (1) {
// t0 = system_timer->counter_low;
// usleep(100);
// t1 = system_timer->counter_low;
// printf ("Elaspsed = %d\n", t1 - t0);
// printf ("Conter high = %d\n", system_timer->counter_high);
// t0 = t1;
// }
// return 0;
// }

View File

@ -0,0 +1 @@
#define VERSION "0"