hw/rpi: USB SOF interrupt filtering

This commit is contained in:
Norman Feske 2014-09-20 22:36:53 +02:00
parent d59d3c684f
commit 58a1e42201
3 changed files with 117 additions and 0 deletions

View File

@ -26,8 +26,111 @@ namespace Genode
* Programmable interrupt controller for core * Programmable interrupt controller for core
*/ */
class Pic; 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 class Genode::Pic : Mmio
{ {
public: public:
@ -51,6 +154,8 @@ class Genode::Pic : Mmio
struct Irq_disable_gpu_2 : Register<0x20, 32> { }; struct Irq_disable_gpu_2 : Register<0x20, 32> { };
struct Irq_disable_basic : Register<0x24, 32> { }; struct Irq_disable_basic : Register<0x24, 32> { };
Usb_dwc_otg _usb;
/** /**
* Return true if specified interrupt is pending * Return true if specified interrupt is pending
*/ */
@ -89,6 +194,12 @@ class Genode::Pic : Mmio
continue; continue;
irq = Board_base::GPU_IRQ_BASE + i; 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; return true;
} }

View File

@ -51,6 +51,9 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
/* IRQ controller */ /* IRQ controller */
{ Board::IRQ_CONTROLLER_BASE, Board::IRQ_CONTROLLER_SIZE }, { 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; return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
} }

View File

@ -48,6 +48,9 @@ namespace Genode
IRQ_CONTROLLER_BASE = 0x2000b200, IRQ_CONTROLLER_BASE = 0x2000b200,
IRQ_CONTROLLER_SIZE = 0x100, IRQ_CONTROLLER_SIZE = 0x100,
USB_DWC_OTG_BASE = 0x20980000,
USB_DWC_OTG_SIZE = 0x20000,
/* timer */ /* timer */
TIMER_IRQ = 0, TIMER_IRQ = 0,