hw: irq controller and timer improvements for Rpi

* renamed rpi pic to Bcm2835_pic
* renamed rpi3 pic to Bcm2837_pic
* added bcm2837 control for setting prescaler value (to fix timer_accuracy)
* changed handling of all interrupts for rpi3 by cascading to bcm2835 pic
* rpi3 irq controller base address made consistent with rpi
* added usb controller memory region for pic on rpi3 (for SOF interrupts)

Ref #3415
This commit is contained in:
Tomasz Gajewski
2021-08-25 23:50:51 +02:00
committed by Christian Helmuth
parent 7db602faec
commit f79d5d640f
10 changed files with 135 additions and 35 deletions

View File

@@ -3,6 +3,7 @@ REP_INC_DIR += src/core/board/rpi3
# add C++ sources # add C++ sources
SRC_CC += kernel/vm_thread_off.cc SRC_CC += kernel/vm_thread_off.cc
SRC_CC += platform_services.cc SRC_CC += platform_services.cc
SRC_CC += spec/arm/bcm2835_pic.cc
SRC_CC += spec/arm/bcm2837_pic.cc SRC_CC += spec/arm/bcm2837_pic.cc
NR_OF_CPUS = 4 NR_OF_CPUS = 4

View File

@@ -26,7 +26,9 @@ Bootstrap::Platform::Board::Board()
Memory_region { ::Board::LOCAL_IRQ_CONTROLLER_BASE, Memory_region { ::Board::LOCAL_IRQ_CONTROLLER_BASE,
::Board::LOCAL_IRQ_CONTROLLER_SIZE }, ::Board::LOCAL_IRQ_CONTROLLER_SIZE },
Memory_region { ::Board::IRQ_CONTROLLER_BASE, Memory_region { ::Board::IRQ_CONTROLLER_BASE,
::Board::IRQ_CONTROLLER_SIZE }) ::Board::IRQ_CONTROLLER_SIZE },
Memory_region { ::Board::USB_DWC_OTG_BASE,
::Board::USB_DWC_OTG_SIZE })
{ } { }

View File

@@ -23,6 +23,9 @@
#include <spec/arm/bcm2835_system_timer.h> #include <spec/arm/bcm2835_system_timer.h>
#include <spec/arm_v6/cpu.h> #include <spec/arm_v6/cpu.h>
namespace Board { using namespace Hw::Rpi_board; }; namespace Board {
using namespace Hw::Rpi_board;
class Pic : public Bcm2835_pic { };
};
#endif /* _CORE__SPEC__RPI__BOARD_H_ */ #endif /* _CORE__SPEC__RPI__BOARD_H_ */

View File

@@ -25,6 +25,7 @@
namespace Board { namespace Board {
using namespace Hw::Rpi3_board; using namespace Hw::Rpi3_board;
class Pic : public Bcm2837_pic { };
enum { TIMER_IRQ = 1 }; enum { TIMER_IRQ = 1 };
}; };

View File

@@ -18,8 +18,8 @@
using namespace Genode; using namespace Genode;
bool Board::Pic::Usb_dwc_otg::_need_trigger_sof(uint32_t host_frame, bool Board::Bcm2835_pic::Usb_dwc_otg::_need_trigger_sof(uint32_t host_frame,
uint32_t scheduled_frame) uint32_t scheduled_frame)
{ {
uint32_t const max_frame = 0x3fff; uint32_t const max_frame = 0x3fff;
@@ -37,7 +37,7 @@ bool Board::Pic::Usb_dwc_otg::_need_trigger_sof(uint32_t host_frame,
} }
Board::Pic:: Board::Bcm2835_pic::
Usb_dwc_otg::Usb_dwc_otg(Global_interrupt_controller &global_irq_ctrl) Usb_dwc_otg::Usb_dwc_otg(Global_interrupt_controller &global_irq_ctrl)
: :
Mmio { Platform::mmio_to_virt(Board::USB_DWC_OTG_BASE) }, Mmio { Platform::mmio_to_virt(Board::USB_DWC_OTG_BASE) },
@@ -49,7 +49,7 @@ Usb_dwc_otg::Usb_dwc_otg(Global_interrupt_controller &global_irq_ctrl)
} }
bool Board::Pic::Usb_dwc_otg::handle_sof() bool Board::Bcm2835_pic::Usb_dwc_otg::handle_sof()
{ {
if (!_is_sof()) if (!_is_sof())
return false; return false;
@@ -72,16 +72,18 @@ bool Board::Pic::Usb_dwc_otg::handle_sof()
} }
Board::Pic::Pic(Global_interrupt_controller &global_irq_ctrl) Board::Bcm2835_pic::Bcm2835_pic(Global_interrupt_controller &global_irq_ctrl,
Genode::addr_t irq_ctrl_base)
: :
Mmio { Platform::mmio_to_virt(Board::IRQ_CONTROLLER_BASE) }, Mmio(Platform::mmio_to_virt(irq_ctrl_base ? irq_ctrl_base
: (Genode::addr_t) Board::IRQ_CONTROLLER_BASE)),
_usb { global_irq_ctrl } _usb { global_irq_ctrl }
{ {
mask(); mask();
} }
bool Board::Pic::take_request(unsigned &irq) bool Board::Bcm2835_pic::take_request(unsigned &irq)
{ {
/* read GPU IRQ status mask */ /* read GPU IRQ status mask */
uint32_t const p1 = read<Irq_pending_gpu_1>(), uint32_t const p1 = read<Irq_pending_gpu_1>(),
@@ -89,6 +91,7 @@ bool Board::Pic::take_request(unsigned &irq)
/* search for lowest set bit in pending masks */ /* search for lowest set bit in pending masks */
for (unsigned i = 0; i < NR_OF_IRQ; i++) { for (unsigned i = 0; i < NR_OF_IRQ; i++) {
if (!_is_pending(i, p1, p2)) if (!_is_pending(i, p1, p2))
continue; continue;
@@ -106,7 +109,7 @@ bool Board::Pic::take_request(unsigned &irq)
} }
void Board::Pic::mask() void Board::Bcm2835_pic::mask()
{ {
write<Irq_disable_basic>(~0); write<Irq_disable_basic>(~0);
write<Irq_disable_gpu_1>(~0); write<Irq_disable_gpu_1>(~0);
@@ -114,18 +117,18 @@ void Board::Pic::mask()
} }
void Board::Pic::unmask(unsigned const i, unsigned) void Board::Bcm2835_pic::unmask(unsigned const i, unsigned)
{ {
if (i < 32) { write<Irq_enable_gpu_1>(1 << i); } if (i < 32) { write<Irq_enable_gpu_1>(1 << i); }
else { write<Irq_enable_gpu_2>(1 << (i - 32)); } else { write<Irq_enable_gpu_2>(1 << (i - 32)); }
} }
void Board::Pic::mask(unsigned const i) void Board::Bcm2835_pic::mask(unsigned const i)
{ {
if (i < 32) { write<Irq_disable_gpu_1>(1 << i); } if (i < 32) { write<Irq_disable_gpu_1>(1 << i); }
else { write<Irq_disable_gpu_2>(1 << (i - 32)); } else { write<Irq_disable_gpu_2>(1 << (i - 32)); }
} }
void Board::Pic::irq_mode(unsigned, unsigned, unsigned) { } void Board::Bcm2835_pic::irq_mode(unsigned, unsigned, unsigned) { }

View File

@@ -20,7 +20,7 @@
namespace Board { namespace Board {
class Global_interrupt_controller; class Global_interrupt_controller;
class Pic; class Bcm2835_pic;
} }
@@ -38,7 +38,7 @@ class Board::Global_interrupt_controller
}; };
class Board::Pic : Genode::Mmio class Board::Bcm2835_pic : Genode::Mmio
{ {
public: public:
@@ -128,7 +128,8 @@ class Board::Pic : Genode::Mmio
public: public:
Pic(Global_interrupt_controller &global_irq_ctrl); Bcm2835_pic(Global_interrupt_controller &global_irq_ctrl,
Genode::addr_t irq_ctrl_base = 0);
bool take_request(unsigned &irq); bool take_request(unsigned &irq);
void finish_request() { } void finish_request() { }

View File

@@ -16,13 +16,14 @@
#include <platform.h> #include <platform.h>
Board::Pic::Pic(Global_interrupt_controller &) Board::Bcm2837_pic::Bcm2837_pic(Global_interrupt_controller &global_irq_ctrl)
: :
Genode::Mmio(Genode::Platform::mmio_to_virt(Board::LOCAL_IRQ_CONTROLLER_BASE)) Genode::Mmio(Genode::Platform::mmio_to_virt(Board::LOCAL_IRQ_CONTROLLER_BASE)),
_bcm2835_pic(global_irq_ctrl, Board::IRQ_CONTROLLER_BASE)
{ } { }
bool Board::Pic::take_request(unsigned & irq) bool Board::Bcm2837_pic::take_request(unsigned & irq)
{ {
unsigned cpu = Genode::Cpu::executing_id(); unsigned cpu = Genode::Cpu::executing_id();
Core_irq_source<0>::access_t src = 0; Core_irq_source<0>::access_t src = 0;
@@ -49,11 +50,17 @@ bool Board::Pic::take_request(unsigned & irq)
return true; return true;
} }
// Gpu interrupt
if (cpu == 0 && Core_irq_source<0>::Gpu::get(src)) {
auto result = _bcm2835_pic.take_request(irq);
return result;
}
return false; return false;
} }
void Board::Pic::_timer_irq(unsigned cpu, bool enable) void Board::Bcm2837_pic::_timer_irq(unsigned cpu, bool enable)
{ {
unsigned v = enable ? 1 : 0; unsigned v = enable ? 1 : 0;
switch (cpu) { switch (cpu) {
@@ -74,7 +81,7 @@ void Board::Pic::_timer_irq(unsigned cpu, bool enable)
} }
void Board::Pic::_ipi(unsigned cpu, bool enable) void Board::Bcm2837_pic::_ipi(unsigned cpu, bool enable)
{ {
unsigned v = enable ? 1 : 0; unsigned v = enable ? 1 : 0;
switch (cpu) { switch (cpu) {
@@ -95,33 +102,31 @@ void Board::Pic::_ipi(unsigned cpu, bool enable)
} }
void Board::Pic::unmask(unsigned const i, unsigned cpu) void Board::Bcm2837_pic::unmask(unsigned const i, unsigned cpu)
{ {
switch (i) { switch (i) {
case TIMER_IRQ: _timer_irq(cpu, true); return; case TIMER_IRQ: _timer_irq(cpu, true); return;
case IPI: _ipi(cpu, true); return; case IPI: _ipi(cpu, true); return;
} }
if (cpu == 0) _bcm2835_pic.unmask(i, cpu);
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
} }
void Board::Pic::mask(unsigned const i) void Board::Bcm2837_pic::mask(unsigned const i)
{ {
unsigned cpu = Genode::Cpu::executing_id(); unsigned cpu = Genode::Cpu::executing_id();
switch (i) { switch (i) {
case TIMER_IRQ: _timer_irq(cpu, false); return; case TIMER_IRQ: _timer_irq(cpu, false); return;
case IPI: _ipi(cpu, false); return; case IPI: _ipi(cpu, false); return;
} }
if (cpu == 0) _bcm2835_pic.mask(i);
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
} }
void Board::Pic::irq_mode(unsigned, unsigned, unsigned) { } void Board::Bcm2837_pic::irq_mode(unsigned, unsigned, unsigned) { }
void Board::Pic::send_ipi(unsigned cpu_target) void Board::Bcm2837_pic::send_ipi(unsigned cpu_target)
{ {
switch (cpu_target) { switch (cpu_target) {
case 0: write<Core_mailbox_set<0>>(1); return; case 0: write<Core_mailbox_set<0>>(1); return;

View File

@@ -16,14 +16,16 @@
#include <util/mmio.h> #include <util/mmio.h>
#include <spec/arm/bcm2835_pic.h>
namespace Board { namespace Board {
class Global_interrupt_controller { }; /* Global_interrupt_controller from Bcm2835_pic */
class Pic; class Bcm2837_pic;
} }
class Board::Pic : Genode::Mmio class Board::Bcm2837_pic : Genode::Mmio
{ {
public: public:
@@ -45,7 +47,20 @@ class Board::Pic : Genode::Mmio
struct Core_mailbox_irq_control : Register<0x50+CPU_NUM*0x4, 32> {}; struct Core_mailbox_irq_control : Register<0x50+CPU_NUM*0x4, 32> {};
template <unsigned CPU_NUM> template <unsigned CPU_NUM>
struct Core_irq_source : Register<0x60+CPU_NUM*0x4, 32> {}; struct Core_irq_source : Register<0x60+CPU_NUM*0x4, 32> {
struct CntPsIrq : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<0, 1> { };
struct CntPnIrq : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<1, 1> { };
struct CntHpIrq : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<2, 1> { };
struct CntVIrq : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<3, 1> { };
struct MBox0 : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<4, 1> { };
struct MBox1 : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<5, 1> { };
struct MBox2 : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<6, 1> { };
struct MBox3 : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<7, 1> { };
struct Gpu : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<8, 1> { };
struct Pmu : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<9, 1> { };
struct Axi : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<10, 1> { };
struct Timer : Register<0x60+CPU_NUM*0x4, 32>::template Bitfield<11, 1> { };
};
template <unsigned CPU_NUM> template <unsigned CPU_NUM>
struct Core_mailbox_set : Register<0x80+CPU_NUM*0x10, 32> {}; struct Core_mailbox_set : Register<0x80+CPU_NUM*0x10, 32> {};
@@ -56,9 +71,11 @@ class Board::Pic : Genode::Mmio
void _ipi(unsigned cpu, bool enable); void _ipi(unsigned cpu, bool enable);
void _timer_irq(unsigned cpu, bool enable); void _timer_irq(unsigned cpu, bool enable);
Bcm2835_pic _bcm2835_pic;
public: public:
Pic(Global_interrupt_controller &); Bcm2837_pic(Global_interrupt_controller &);
bool take_request(unsigned &irq); bool take_request(unsigned &irq);
void finish_request() { } void finish_request() { }

View File

@@ -29,11 +29,17 @@ namespace Hw::Rpi3_board {
UART_SIZE = 0x1000, UART_SIZE = 0x1000,
UART_CLOCK = 250000000, UART_CLOCK = 250000000,
IRQ_CONTROLLER_BASE = 0x3f00b000, IRQ_CONTROLLER_BASE = 0x3f00b200,
IRQ_CONTROLLER_SIZE = 0x1000, IRQ_CONTROLLER_SIZE = 0x1000,
LOCAL_IRQ_CONTROLLER_BASE = 0x40000000, LOCAL_IRQ_CONTROLLER_BASE = 0x40000000,
LOCAL_IRQ_CONTROLLER_SIZE = 0x1000, LOCAL_IRQ_CONTROLLER_SIZE = 0x1000,
USB_DWC_OTG_BASE = 0x3f980000,
USB_DWC_OTG_SIZE = 0x20000,
/* USB host controller */
DWC_IRQ = 9,
}; };
}; };

View File

@@ -0,0 +1,61 @@
/*
* \brief Driver for the platform specific functionality for bcm2837
* \author Tomasz Gajewski
* \date 2019-12-28
*/
/*
* Copyright (C) 2011-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__DRIVERS__PLATFORM__BCM2837_CONTROL_H_
#define _INCLUDE__DRIVERS__PLATFORM__BCM2837_CONTROL_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode { class Bcm2837_control; }
class Genode::Bcm2837_control : Mmio
{
public:
struct ControlRegister : public Register<0x0, 32>
{
struct CoreTimeClockSource : Bitfield<8,1> { };
struct TimerIncrement : Bitfield<9,1> { };
};
struct CoreTimerPrescaler : public Register<0x8, 32>
{
};
inline Bcm2837_control(addr_t const base);
inline void initialize_timer_frequency();
};
Genode::Bcm2837_control::Bcm2837_control(addr_t const base)
:
Mmio(base)
{ }
void Genode::Bcm2837_control::initialize_timer_frequency()
{
/*
* Set prescaler value to achieve divider value equal to 1.
* Value taken from chapter "3.1.1 Timer clock" from QA7_rev3.4.pdf
* document describing the BCM2836 chip.
*/
write<CoreTimerPrescaler>(0x80000000);
}
#endif /* _INCLUDE__DRIVERS__PLATFORM__BCM2837_CONTROL_H_ */