mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
hw/rpi: USB SOF interrupt filtering
This commit is contained in:
parent
d59d3c684f
commit
58a1e42201
@ -26,8 +26,111 @@ namespace Genode
|
||||
* Programmable interrupt controller for core
|
||||
*/
|
||||
class Pic;
|
||||
|
||||
class Usb_dwc_otg;
|
||||
}
|
||||
|
||||
|
||||
class Genode::Usb_dwc_otg : Mmio
|
||||
{
|
||||
private:
|
||||
|
||||
struct Core_irq_status : Register<0x14, 32>
|
||||
{
|
||||
struct Sof : Bitfield<3, 1> { };
|
||||
};
|
||||
|
||||
struct Guid : Register<0x3c, 32>
|
||||
{
|
||||
struct Num : Bitfield<0, 14> { };
|
||||
|
||||
/*
|
||||
* The USB driver set 'Num' to a defined value
|
||||
*/
|
||||
struct Num_valid : Bitfield<31, 1> { };
|
||||
|
||||
/*
|
||||
* Filter is not used, overridden by the USB driver
|
||||
*/
|
||||
struct Kick : Bitfield<30, 1> { };
|
||||
};
|
||||
|
||||
struct Host_frame_number : Register<0x408, 32>
|
||||
{
|
||||
struct Num : Bitfield<0, 14> { };
|
||||
};
|
||||
|
||||
bool _is_sof() const
|
||||
{
|
||||
return read<Core_irq_status::Sof>();
|
||||
}
|
||||
|
||||
static bool _need_trigger_sof(uint32_t host_frame,
|
||||
uint32_t scheduled_frame)
|
||||
{
|
||||
uint32_t const max_frame = 0x3fff;
|
||||
|
||||
if (host_frame < scheduled_frame) {
|
||||
if (scheduled_frame - host_frame < max_frame / 2)
|
||||
return false; /* scheduled frame not reached yet */
|
||||
else
|
||||
return true; /* scheduled frame passed, host frame wrapped */
|
||||
} else {
|
||||
if (host_frame - scheduled_frame < max_frame / 2)
|
||||
return true; /* scheduled frame passed */
|
||||
else
|
||||
return false; /* scheduled frame wrapped, not reached */
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Usb_dwc_otg() : Mmio(Board::USB_DWC_OTG_BASE)
|
||||
{
|
||||
write<Guid::Num>(0);
|
||||
write<Guid::Num_valid>(false);
|
||||
write<Guid::Kick>(false);
|
||||
}
|
||||
|
||||
bool handle_sof()
|
||||
{
|
||||
if (!_is_sof())
|
||||
return false;
|
||||
|
||||
static int cnt, stat_cnt, filter_cnt, trigger_cnt, kick_cnt;
|
||||
|
||||
stat_cnt++;
|
||||
if (stat_cnt == 8000) {
|
||||
PLOG("kicked: %d filtered: %d triggered: %d", kick_cnt, filter_cnt, trigger_cnt);
|
||||
stat_cnt = 0;
|
||||
}
|
||||
|
||||
cnt++;
|
||||
if (cnt == 8*20) {
|
||||
cnt = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read<Guid::Kick>())
|
||||
kick_cnt++;
|
||||
|
||||
if (!read<Guid::Num_valid>() || read<Guid::Kick>())
|
||||
return false;
|
||||
|
||||
if (_need_trigger_sof(read<Host_frame_number::Num>(), read<Guid::Num>())) {
|
||||
trigger_cnt++;
|
||||
return false;
|
||||
}
|
||||
|
||||
filter_cnt++;
|
||||
|
||||
write<Core_irq_status::Sof>(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Genode::Pic : Mmio
|
||||
{
|
||||
public:
|
||||
@ -51,6 +154,8 @@ class Genode::Pic : Mmio
|
||||
struct Irq_disable_gpu_2 : Register<0x20, 32> { };
|
||||
struct Irq_disable_basic : Register<0x24, 32> { };
|
||||
|
||||
Usb_dwc_otg _usb;
|
||||
|
||||
/**
|
||||
* Return true if specified interrupt is pending
|
||||
*/
|
||||
@ -89,6 +194,12 @@ class Genode::Pic : Mmio
|
||||
continue;
|
||||
|
||||
irq = Board_base::GPU_IRQ_BASE + i;
|
||||
|
||||
/* handle SOF interrupts locally, filter from the user land */
|
||||
if (irq == Board_base::DWC_IRQ)
|
||||
if (_usb.handle_sof())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,9 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
|
||||
|
||||
/* IRQ controller */
|
||||
{ Board::IRQ_CONTROLLER_BASE, Board::IRQ_CONTROLLER_SIZE },
|
||||
|
||||
/* DWC OTG USB controller (used for in-kernel SOF IRQ handling) */
|
||||
{ Board::USB_DWC_OTG_BASE, Board::USB_DWC_OTG_SIZE },
|
||||
};
|
||||
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
|
||||
}
|
||||
|
@ -48,6 +48,9 @@ namespace Genode
|
||||
IRQ_CONTROLLER_BASE = 0x2000b200,
|
||||
IRQ_CONTROLLER_SIZE = 0x100,
|
||||
|
||||
USB_DWC_OTG_BASE = 0x20980000,
|
||||
USB_DWC_OTG_SIZE = 0x20000,
|
||||
|
||||
/* timer */
|
||||
TIMER_IRQ = 0,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user