diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index ff576344..1195f18c 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -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 diff --git a/src/raspberrypi/common.h b/src/raspberrypi/common.h new file mode 100644 index 00000000..52341c3e --- /dev/null +++ b/src/raspberrypi/common.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Alejandro Mery + * + * 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 . + */ +#ifndef _SUNXI_TOOLS_COMMON_H +#define _SUNXI_TOOLS_COMMON_H + +#include /* 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 */ \ No newline at end of file diff --git a/src/raspberrypi/controllers/scsi_controller.cpp b/src/raspberrypi/controllers/scsi_controller.cpp index 7864f0c3..dc06e2e5 100644 --- a/src/raspberrypi/controllers/scsi_controller.cpp +++ b/src/raspberrypi/controllers/scsi_controller.cpp @@ -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; } diff --git a/src/raspberrypi/hal/allwinner_hal.cpp b/src/raspberrypi/hal/allwinner_hal.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/raspberrypi/hal/allwinner_hal.h b/src/raspberrypi/hal/allwinner_hal.h new file mode 100644 index 00000000..e69de29b diff --git a/src/raspberrypi/hal/gpiobus.cpp b/src/raspberrypi/hal/gpiobus.cpp index c558cfb8..ad65b7a6 100644 --- a/src/raspberrypi/hal/gpiobus.cpp +++ b/src/raspberrypi/hal/gpiobus.cpp @@ -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; } diff --git a/src/raspberrypi/hal/sbc_version.cpp b/src/raspberrypi/hal/sbc_version.cpp new file mode 100644 index 00000000..eeffb9f3 --- /dev/null +++ b/src/raspberrypi/hal/sbc_version.cpp @@ -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 +#include +#include + +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 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 \ No newline at end of file diff --git a/src/raspberrypi/hal/sbc_version.h b/src/raspberrypi/hal/sbc_version.h new file mode 100644 index 00000000..791897f8 --- /dev/null +++ b/src/raspberrypi/hal/sbc_version.h @@ -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 +#include + +//=========================================================================== +// +// 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 m_proc_device_tree_mapping; + + static const std::string m_device_tree_model_path; + + static DWORD GetDeviceTreeRanges(const char *filename, DWORD offset); + +}; \ No newline at end of file diff --git a/src/raspberrypi/hal/systimer.cpp b/src/raspberrypi/hal/systimer.cpp index 6af7dbe6..00bc98e1 100644 --- a/src/raspberrypi/hal/systimer.cpp +++ b/src/raspberrypi/hal/systimer.cpp @@ -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 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(); + private_instance->Init(); + } + else if(SBC_Version::IsBananaPi()){ + private_instance = std::make_shared(); + 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) { diff --git a/src/raspberrypi/hal/systimer.h b/src/raspberrypi/hal/systimer.h index 8f4b31d9..91e3fce8 100644 --- a/src/raspberrypi/hal/systimer.h +++ b/src/raspberrypi/hal/systimer.h @@ -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 private_instance; }; diff --git a/src/raspberrypi/hal/systimer_allwinner.cpp b/src/raspberrypi/hal/systimer_allwinner.cpp new file mode 100644 index 00000000..d78ff723 --- /dev/null +++ b/src/raspberrypi/hal/systimer_allwinner.cpp @@ -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 + +#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(); + private_instance->Init(); + } + else if(SBC_Version::IsBananaPi()){ + private_instance = std::make_shared(); + 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); +} diff --git a/src/raspberrypi/hal/systimer_allwinner.h b/src/raspberrypi/hal/systimer_allwinner.h new file mode 100644 index 00000000..7c1fd807 --- /dev/null +++ b/src/raspberrypi/hal/systimer_allwinner.h @@ -0,0 +1,42 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI Reloaded +// for Raspberry Pi +// +// Copyright (C) 2022 akuker +// +// [ High resolution timer ] +// +//--------------------------------------------------------------------------- +#pragma once + +#include +#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 +}; diff --git a/src/raspberrypi/hal/systimer_raspberry.cpp b/src/raspberrypi/hal/systimer_raspberry.cpp new file mode 100644 index 00000000..0e216d42 --- /dev/null +++ b/src/raspberrypi/hal/systimer_raspberry.cpp @@ -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 + +#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(); + private_instance->Init(); + } + else if(SBC_Version::IsBananaPi()){ + private_instance = std::make_shared(); + 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); +} diff --git a/src/raspberrypi/hal/systimer_raspberry.h b/src/raspberrypi/hal/systimer_raspberry.h new file mode 100644 index 00000000..21617b1a --- /dev/null +++ b/src/raspberrypi/hal/systimer_raspberry.h @@ -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 +#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 +}; diff --git a/src/raspberrypi/mem-info b/src/raspberrypi/mem-info new file mode 100755 index 00000000..ff85dbde Binary files /dev/null and b/src/raspberrypi/mem-info differ diff --git a/src/raspberrypi/mem-info.c b/src/raspberrypi/mem-info.c new file mode 100644 index 00000000..9cba9bde --- /dev/null +++ b/src/raspberrypi/mem-info.c @@ -0,0 +1,793 @@ +/* + * Copyright (C) 2012 Floris Bos + * Copyright (c) 2014 Luc Verhaegen + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 \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; +} \ No newline at end of file diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 2bccfb25..6e1c86f4 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -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; diff --git a/src/raspberrypi/rasdump.cpp b/src/raspberrypi/rasdump.cpp index e31fe570..2c7bc58f 100644 --- a/src/raspberrypi/rasdump.cpp +++ b/src/raspberrypi/rasdump.cpp @@ -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; diff --git a/src/raspberrypi/registers b/src/raspberrypi/registers new file mode 100755 index 00000000..465aebec Binary files /dev/null and b/src/raspberrypi/registers differ diff --git a/src/raspberrypi/registers.c b/src/raspberrypi/registers.c new file mode 100644 index 00000000..240f46f2 --- /dev/null +++ b/src/raspberrypi/registers.c @@ -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 +#include +#include +#include +#include +#include + + +#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; +// } \ No newline at end of file diff --git a/src/raspberrypi/registers.d b/src/raspberrypi/registers.d new file mode 100644 index 00000000..550d2519 --- /dev/null +++ b/src/raspberrypi/registers.d @@ -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: diff --git a/src/raspberrypi/registers_raspi.c b/src/raspberrypi/registers_raspi.c new file mode 100644 index 00000000..42fdf7cb --- /dev/null +++ b/src/raspberrypi/registers_raspi.c @@ -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 +#include +#include +#include +#include +#include + +// #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; +// } \ No newline at end of file diff --git a/src/raspberrypi/version.h b/src/raspberrypi/version.h new file mode 100644 index 00000000..ffc39266 --- /dev/null +++ b/src/raspberrypi/version.h @@ -0,0 +1 @@ +#define VERSION "0" \ No newline at end of file