diff --git a/repos/dde_linux/src/include/lx_kit/timer.h b/repos/dde_linux/src/include/lx_kit/timer.h
index 959db89710..ae82bdb297 100644
--- a/repos/dde_linux/src/include/lx_kit/timer.h
+++ b/repos/dde_linux/src/include/lx_kit/timer.h
@@ -36,6 +36,9 @@ namespace Lx {
unsigned long *jiffies_ptr = nullptr);
void timer_update_jiffies();
+
+ typedef unsigned long (*jiffies_update_func)(void);
+ void register_jiffies_func(jiffies_update_func func);
}
diff --git a/repos/dde_linux/src/lib/usb/spec/rpi/platform.cc b/repos/dde_linux/src/lib/usb/spec/rpi/platform.cc
index 8d8d25e622..2d255c3a6c 100644
--- a/repos/dde_linux/src/lib/usb/spec/rpi/platform.cc
+++ b/repos/dde_linux/src/lib/usb/spec/rpi/platform.cc
@@ -12,14 +12,18 @@
*/
/* Genode includes */
+#include
#include
#include
#include
#include
+
/* emulation */
#include
#include
+#include
+
/* dwc-otg */
#define new new_
@@ -31,6 +35,122 @@
using namespace Genode;
+namespace Genode { template class Sp804_base; }
+
+
+
+/**
+ * Basic driver for the ARM SP804 timer
+ */
+template
+class Genode::Sp804_base : public Mmio
+{
+ enum {
+ TICS_PER_MS = CLK / 1000,
+ };
+
+ /**
+ * Holds value that shall be loaded to the timer value register
+ */
+ struct Load : Register<0x0, 32> { };
+
+ /**
+ * Timer value register
+ */
+ struct Value : Register<0x4, 32> { enum { MAX_VALUE = 0xffffffff }; };
+
+ /**
+ * Timer control register
+ */
+ struct Control : Register<0x8, 8>
+ {
+ struct Oneshot : Bitfield<0,1> { };
+ struct Size : Bitfield<1,1> { };
+ struct Pre : Bitfield<2,2> { };
+ struct Int_en : Bitfield<5,1> { };
+ struct Mode : Bitfield<6,1> { };
+ struct Timer_en : Bitfield<7,1> { };
+ };
+
+ /**
+ * Clears the timer interrupt
+ */
+ struct Int_clr : Register<0xc, 1> { };
+
+ unsigned _last_tick = Value::MAX_VALUE;
+
+ public:
+
+ /**
+ * Constructor, clears interrupt output
+ */
+ Sp804_base(addr_t const mmio_base) : Mmio(mmio_base)
+ {
+ /* clear irq */
+ write(1);
+
+ /* disabble and configure */
+ write(0);
+ write(Control::Mode::bits(0) | /* free running */
+ Control::Int_en::bits(0) | /* IRQ disabled */
+ Control::Pre::bits(0) | /* clk divider 1 */
+ Control::Size::bits(1) | /* 32 bit */
+ Control::Oneshot::bits(0)); /* one-shot off */
+
+ /* start */
+ write(Value::MAX_VALUE);
+ write(1);
+ }
+
+ unsigned long update_jiffies()
+ {
+ unsigned tick = read();
+
+ /* timer runs backwards */
+ unsigned delta = ticks_to_ms(_last_tick - tick);
+
+ /* delta < 1 jiffie */
+ if (!msecs_to_jiffies(delta))
+ return jiffies;
+
+ jiffies += msecs_to_jiffies(delta);
+ _last_tick = tick;
+ return jiffies;
+ }
+
+ /**
+ * Translate native timer value to milliseconds
+ */
+ static unsigned long ticks_to_ms(unsigned long const tics) {
+ return tics / TICS_PER_MS; }
+};
+
+
+enum { TIMER_MMIO_BASE = 0x2000b400,
+ TIMER_MMIO_SIZE = 0x100,
+ TIMER_CLOCK = 992*1000 };
+
+struct Platform_timer : Attached_io_mem_dataspace,
+ Sp804_base
+{
+ Platform_timer() :
+ Attached_io_mem_dataspace(TIMER_MMIO_BASE, TIMER_MMIO_SIZE),
+ Sp804_base((Genode::addr_t)local_addr())
+ { }
+
+ static Platform_timer &instance()
+ {
+ static Platform_timer _timer;
+ return _timer;
+ }
+};
+
+
+static unsigned long jiffies_update_func()
+{
+ return Platform_timer::instance().update_jiffies();
+}
+
/************************************************
** Resource info passed to the dwc_otg driver **
@@ -165,6 +285,12 @@ extern "C" int module_smsc95xx_driver_init();
void platform_hcd_init(Services *services)
{
+ /* enable timer */
+ Platform_timer::instance();
+
+ /* use costum jiffies update function and the Sp804 timer */
+ Lx::register_jiffies_func(jiffies_update_func);
+
/* enable USB power */
Platform::Connection platform;
platform.power_state(Platform::Session::POWER_USB_HCD, true);
diff --git a/repos/dde_linux/src/lx_kit/timer.cc b/repos/dde_linux/src/lx_kit/timer.cc
index cc53c9ee2d..93db0dea84 100644
--- a/repos/dde_linux/src/lx_kit/timer.cc
+++ b/repos/dde_linux/src/lx_kit/timer.cc
@@ -86,6 +86,7 @@ class Lx_kit::Timer : public Lx::Timer
Lx::Task _timer_task;
Genode::Signal_rpc_member _dispatcher;
Genode::Tslab _timer_alloc;
+ Lx::jiffies_update_func _jiffies_func = nullptr;
/**
* Lookup local timer
@@ -289,7 +290,10 @@ class Lx_kit::Timer : public Lx::Timer
}
void update_jiffies() {
- _jiffies = msecs_to_jiffies(_timer_conn.elapsed_ms()); }
+ _jiffies = _jiffies_func ? _jiffies_func() : msecs_to_jiffies(_timer_conn.elapsed_ms()); }
+
+ void register_jiffies_func(Lx::jiffies_update_func func) {
+ _jiffies_func = func; }
};
@@ -308,3 +312,9 @@ void Lx::timer_update_jiffies()
{
timer().update_jiffies();
}
+
+
+void Lx::register_jiffies_func(jiffies_update_func func)
+{
+ dynamic_cast(timer()).register_jiffies_func(func);
+}