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); +}