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
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += platform_services.cc
SRC_CC += spec/arm/bcm2835_pic.cc
SRC_CC += spec/arm/bcm2837_pic.cc
NR_OF_CPUS = 4

View File

@ -26,7 +26,9 @@ Bootstrap::Platform::Board::Board()
Memory_region { ::Board::LOCAL_IRQ_CONTROLLER_BASE,
::Board::LOCAL_IRQ_CONTROLLER_SIZE },
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_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_ */

View File

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

View File

@ -18,7 +18,7 @@
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 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)
:
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())
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 }
{
mask();
}
bool Board::Pic::take_request(unsigned &irq)
bool Board::Bcm2835_pic::take_request(unsigned &irq)
{
/* read GPU IRQ status mask */
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 */
for (unsigned i = 0; i < NR_OF_IRQ; i++) {
if (!_is_pending(i, p1, p2))
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_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); }
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); }
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 {
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:
@ -128,7 +128,8 @@ class Board::Pic : Genode::Mmio
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);
void finish_request() { }

View File

@ -16,13 +16,14 @@
#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();
Core_irq_source<0>::access_t src = 0;
@ -49,11 +50,17 @@ bool Board::Pic::take_request(unsigned & irq)
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;
}
void Board::Pic::_timer_irq(unsigned cpu, bool enable)
void Board::Bcm2837_pic::_timer_irq(unsigned cpu, bool enable)
{
unsigned v = enable ? 1 : 0;
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;
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) {
case TIMER_IRQ: _timer_irq(cpu, true); return;
case IPI: _ipi(cpu, true); return;
}
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
if (cpu == 0) _bcm2835_pic.unmask(i, cpu);
}
void Board::Pic::mask(unsigned const i)
void Board::Bcm2837_pic::mask(unsigned const i)
{
unsigned cpu = Genode::Cpu::executing_id();
switch (i) {
case TIMER_IRQ: _timer_irq(cpu, false); return;
case IPI: _ipi(cpu, false); return;
}
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
if (cpu == 0) _bcm2835_pic.mask(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) {
case 0: write<Core_mailbox_set<0>>(1); return;

View File

@ -16,14 +16,16 @@
#include <util/mmio.h>
#include <spec/arm/bcm2835_pic.h>
namespace Board {
class Global_interrupt_controller { };
class Pic;
/* Global_interrupt_controller from Bcm2835_pic */
class Bcm2837_pic;
}
class Board::Pic : Genode::Mmio
class Board::Bcm2837_pic : Genode::Mmio
{
public:
@ -45,7 +47,20 @@ class Board::Pic : Genode::Mmio
struct Core_mailbox_irq_control : Register<0x50+CPU_NUM*0x4, 32> {};
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>
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 _timer_irq(unsigned cpu, bool enable);
Bcm2835_pic _bcm2835_pic;
public:
Pic(Global_interrupt_controller &);
Bcm2837_pic(Global_interrupt_controller &);
bool take_request(unsigned &irq);
void finish_request() { }

View File

@ -29,11 +29,17 @@ namespace Hw::Rpi3_board {
UART_SIZE = 0x1000,
UART_CLOCK = 250000000,
IRQ_CONTROLLER_BASE = 0x3f00b000,
IRQ_CONTROLLER_BASE = 0x3f00b200,
IRQ_CONTROLLER_SIZE = 0x1000,
LOCAL_IRQ_CONTROLLER_BASE = 0x40000000,
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_ */