draft: aarch64: add irq_bcm2835. Need refactoring
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use crate::arch::device::irqchip::IRQ_CHIP;
|
||||
use crate::context::timeout;
|
||||
use crate::device::cpu::registers::control_regs;
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use crate::interrupt::irq::trigger;
|
||||
use crate::time;
|
||||
use crate::context;
|
||||
use crate::dtb::DTB_BINARY;
|
||||
|
||||
use super::irqchip::InterruptHandler;
|
||||
use super::irqchip::register_irq;
|
||||
@@ -21,9 +25,34 @@ bitflags! {
|
||||
pub unsafe fn init() {
|
||||
let mut timer = GenericTimer{ clk_freq: 0, reload_count: 0};
|
||||
timer.init();
|
||||
//TODO: REMOVE HARD CODE IRQ NUMBER
|
||||
register_irq(30, Box::new(timer));
|
||||
IRQ_CHIP.irq_enable(30);
|
||||
let data = DTB_BINARY.get().unwrap();
|
||||
let fdt = fdt::DeviceTree::new(data).unwrap();
|
||||
if let Some(node) = find_compatible_node(&fdt, "arm,armv7-timer") {
|
||||
let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap();
|
||||
let mut intr_data = Vec::new();
|
||||
for chunk in interrupts.data.chunks(4) {
|
||||
let val = BE::read_u32(chunk);
|
||||
intr_data.push(val);
|
||||
}
|
||||
let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx;
|
||||
if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) {
|
||||
let phandle = BE::read_u32(interrupt_parent.data);
|
||||
let mut i = 0;
|
||||
while i < IRQ_CHIP.irq_chip_list.chips.len() {
|
||||
let item = &IRQ_CHIP.irq_chip_list.chips[i];
|
||||
if item.phandle == phandle {
|
||||
ic_idx = i;
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
//PHYS_NONSECURE_PPI only
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 1).unwrap();
|
||||
println!("generic_timer virq = {}", virq);
|
||||
register_irq(virq as u32, Box::new(timer));
|
||||
IRQ_CHIP.irq_enable(virq as u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GenericTimer {
|
||||
|
||||
@@ -6,7 +6,7 @@ use byteorder::{ByteOrder, BE};
|
||||
use crate::{device::io_mmap, init::device_tree::find_compatible_node};
|
||||
use syscall::{Result, error::{Error, EINVAL}};
|
||||
|
||||
use super::InterruptController;
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
static GICD_CTLR: u32 = 0x000;
|
||||
static GICD_TYPER: u32 = 0x004;
|
||||
@@ -24,6 +24,7 @@ static GICC_PMR: u32 = 0x0004;
|
||||
pub struct GenericInterruptController {
|
||||
gic_dist_if: GicDistIf,
|
||||
gic_cpu_if: GicCpuIf,
|
||||
irq_range: (usize, usize),
|
||||
}
|
||||
|
||||
impl GenericInterruptController {
|
||||
@@ -37,18 +38,13 @@ impl GenericInterruptController {
|
||||
address: 0,
|
||||
};
|
||||
|
||||
GenericInterruptController { gic_dist_if, gic_cpu_if }
|
||||
GenericInterruptController { gic_dist_if, gic_cpu_if, irq_range: (0, 0) }
|
||||
}
|
||||
pub fn parse(fdt: Option<&DeviceTree>) -> Result<(usize, usize, usize, usize)> {
|
||||
match fdt {
|
||||
None => Err(Error::new(EINVAL)),
|
||||
Some(dtb) => {
|
||||
if let Some(node) = find_compatible_node(dtb, "arm,cortex-a15-gic") {
|
||||
return GenericInterruptController::parse_inner(&node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, usize, usize)> {
|
||||
if let Some(node) = find_compatible_node(fdt, "arm,cortex-a15-gic") {
|
||||
return GenericInterruptController::parse_inner(&node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
fn parse_inner(node: &Node) -> Result<(usize, usize, usize, usize)> {
|
||||
@@ -79,9 +75,11 @@ impl GenericInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController for GenericInterruptController {
|
||||
fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()> {
|
||||
let (dist_addr, dist_size, cpu_addr, cpu_size) =
|
||||
GenericInterruptController::parse(fdt).unwrap();
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>> {
|
||||
let (dist_addr, dist_size, cpu_addr, cpu_size) = match GenericInterruptController::parse(fdt) {
|
||||
Ok(regs) => regs,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
//TODO: do kernel memory map using node.ranges
|
||||
@@ -98,9 +96,23 @@ impl InterruptController for GenericInterruptController {
|
||||
self.gic_cpu_if.write(GICC_CTLR, 1);
|
||||
// Set CPU0's Interrupt Priority Mask
|
||||
self.gic_cpu_if.write(GICC_PMR, 0xff);
|
||||
|
||||
}
|
||||
Ok(())
|
||||
let idx = *irq_idx;
|
||||
let cnt = if self.gic_dist_if.nirqs > 1024 { 1024 } else { self.gic_dist_if.nirqs as usize };
|
||||
let mut i: usize = 0;
|
||||
//only support linear irq map now.
|
||||
while i < cnt && (idx + i < 1024) {
|
||||
irq_desc[idx + i].basic.ic_idx = ic_idx;
|
||||
irq_desc[idx + i].basic.ic_irq = i as u32;
|
||||
irq_desc[idx + i].basic.used = true;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
println!("gic irq_range = ({}, {})", idx, idx + cnt);
|
||||
self.irq_range = (idx, idx + cnt);
|
||||
*irq_idx = idx + cnt;
|
||||
Ok(None)
|
||||
}
|
||||
fn irq_ack(&mut self) -> u32 {
|
||||
unsafe { self.gic_cpu_if.irq_ack() }
|
||||
@@ -114,6 +126,33 @@ impl InterruptController for GenericInterruptController {
|
||||
fn irq_disable(&mut self, irq_num: u32) {
|
||||
unsafe { self.gic_dist_if.irq_disable(irq_num) }
|
||||
}
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize> {
|
||||
let mut off: usize = 0;
|
||||
let mut i = 0;
|
||||
for chunk in irq_data.chunks(3) {
|
||||
if i == idx {
|
||||
match chunk[0] {
|
||||
0 => off = chunk[1] as usize + 32, //SPI
|
||||
1 => off = chunk[1] as usize + 16, //PPI,
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
}
|
||||
off += self.irq_range.0;
|
||||
return Ok(off);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
if hwirq >= self.gic_dist_if.nirqs {
|
||||
None
|
||||
} else {
|
||||
Some(self.irq_range.0 + hwirq as usize)
|
||||
}
|
||||
}
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GicDistIf {
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{DeviceTree, Node};
|
||||
use crate::arch::device::irqchip::IRQ_CHIP;
|
||||
|
||||
use crate::{device::io_mmap, init::device_tree::find_compatible_node};
|
||||
use syscall::{Result, error::{Error, EINVAL}};
|
||||
|
||||
use super::InterruptController;
|
||||
use super::{InterruptController, IrqDesc, InterruptHandler};
|
||||
|
||||
#[inline(always)]
|
||||
fn ffs(num: u32) -> u32 {
|
||||
@@ -39,49 +42,67 @@ fn ffs(num: u32) -> u32 {
|
||||
r
|
||||
}
|
||||
|
||||
const PENDING_0: u32 = 0x200;
|
||||
const PENDING_1: u32 = 0x204;
|
||||
const PENDING_2: u32 = 0x208;
|
||||
const FIQ_CTRL: u32 = 0x20c;
|
||||
const ENABLE_0: u32 = 0x218;
|
||||
const ENABLE_1: u32 = 0x210;
|
||||
const ENABLE_2: u32 = 0x214;
|
||||
const DISABLE_0: u32 = 0x224;
|
||||
const DISABLE_1: u32 = 0x21c;
|
||||
const DISABLE_2: u32 = 0x220;
|
||||
|
||||
const PENDING_0: u32 = 0x0;
|
||||
const PENDING_1: u32 = 0x4;
|
||||
const PENDING_2: u32 = 0x8;
|
||||
const FIQ_CTRL: u32 = 0xc;
|
||||
const ENABLE_0: u32 = 0x18;
|
||||
const ENABLE_1: u32 = 0x10;
|
||||
const ENABLE_2: u32 = 0x14;
|
||||
const DISABLE_0: u32 = 0x24;
|
||||
const DISABLE_1: u32 = 0x1c;
|
||||
const DISABLE_2: u32 = 0x20;
|
||||
|
||||
pub struct Bcm2835ArmInterruptController {
|
||||
pub address: usize,
|
||||
pub irq_range: (usize, usize),
|
||||
}
|
||||
|
||||
|
||||
impl Bcm2835ArmInterruptController {
|
||||
pub fn new() -> Self {
|
||||
Bcm2835ArmInterruptController { address: 0 }
|
||||
Bcm2835ArmInterruptController { address: 0, irq_range: (0, 0) }
|
||||
}
|
||||
pub fn parse(fdt: Option<&DeviceTree>) -> Result<(usize, usize)> {
|
||||
match fdt {
|
||||
//TODO: remove hard code for qemu-virt
|
||||
None => Err(Error::new(EINVAL)),
|
||||
Some(dtb) => {
|
||||
//TODO: try to parse dtb using stable library
|
||||
if let Some(node) = find_compatible_node(dtb, "brcm,bcm2835-armctrl-ic") {
|
||||
return Bcm2835ArmInterruptController::parse_inner(&node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, Option<usize>)> {
|
||||
//TODO: try to parse dtb using stable library
|
||||
if let Some(node) = find_compatible_node(fdt, "brcm,bcm2836-armctrl-ic") {
|
||||
return unsafe { Bcm2835ArmInterruptController::parse_inner(&node) };
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
fn parse_inner(node: &Node) -> Result<(usize, usize)> {
|
||||
unsafe fn parse_inner(node: &Node) -> Result<(usize, usize, Option<usize>)> {
|
||||
//assert address_cells == 0x1, size_cells == 0x1
|
||||
let reg = node.properties().find(|p| p.name.contains("reg")).unwrap();
|
||||
let (base, size) = reg.data.split_at(4);
|
||||
let base = BE::read_u32(base);
|
||||
let size = BE::read_u32(size);
|
||||
let mut ret_virq = None;
|
||||
|
||||
Ok((base as usize, size as usize))
|
||||
if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) {
|
||||
let phandle = BE::read_u32(interrupt_parent.data);
|
||||
let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap();
|
||||
let mut intr_data = Vec::new();
|
||||
for chunk in interrupts.data.chunks(4) {
|
||||
let val = BE::read_u32(chunk);
|
||||
intr_data.push(val);
|
||||
}
|
||||
let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx;
|
||||
let mut i = 0;
|
||||
while i < IRQ_CHIP.irq_chip_list.chips.len() {
|
||||
let item = &IRQ_CHIP.irq_chip_list.chips[i];
|
||||
if item.phandle == phandle {
|
||||
ic_idx = i;
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
//PHYS_NONSECURE_PPI only
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 0).unwrap();
|
||||
println!("bcm2835arm_ctrl virq = {}", virq);
|
||||
ret_virq = Some(virq);
|
||||
}
|
||||
Ok((base as usize, size as usize, ret_virq))
|
||||
}
|
||||
|
||||
unsafe fn init(&mut self) {
|
||||
@@ -105,38 +126,55 @@ impl Bcm2835ArmInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController for Bcm2835ArmInterruptController {
|
||||
fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()> {
|
||||
let (base, size) = match Bcm2835ArmInterruptController::parse(fdt) {
|
||||
Ok((a, b)) => (a, b),
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>> {
|
||||
let (base, size, virq) = match Bcm2835ArmInterruptController::parse(fdt) {
|
||||
Ok((a, b, c)) => (a, b, c),
|
||||
Err(_) => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
unsafe {
|
||||
io_mmap(base, size);
|
||||
|
||||
self.address = base;
|
||||
self.address = base + crate::PHYS_OFFSET;
|
||||
|
||||
self.init();
|
||||
let idx = *irq_idx;
|
||||
let cnt = 3 << 5; //3 * 32 irqs, basic == 8, reg1 = 32, reg2 = 32
|
||||
let mut i: usize = 0;
|
||||
//only support linear irq map now.
|
||||
while i < cnt && (idx + i < 1024) {
|
||||
irq_desc[idx + i].basic.ic_idx = ic_idx;
|
||||
irq_desc[idx + i].basic.ic_irq = i as u32;
|
||||
irq_desc[idx + i].basic.used = true;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
println!("bcm2835 irq_range = ({}, {})", idx, idx + cnt);
|
||||
self.irq_range = (idx, idx + cnt);
|
||||
*irq_idx = idx + cnt;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(virq)
|
||||
}
|
||||
|
||||
fn irq_ack(&mut self) -> u32 {
|
||||
//TODO: support smp self.read(LOCAL_IRQ_PENDING + 4 * cpu)
|
||||
//assert cpu == 0
|
||||
let sources = unsafe { self.read(PENDING_0) };
|
||||
let sources = unsafe { self.read(PENDING_0) & 0x3ff };
|
||||
let pending_num = ffs(sources) - 1;
|
||||
match pending_num {
|
||||
num@0..=7 => return num,
|
||||
num@0..=7 => {
|
||||
println!("inner interrupt {}", num);
|
||||
return num
|
||||
},
|
||||
8 => {
|
||||
let sources1 = unsafe { self.read(PENDING_1) };
|
||||
let irq_0_31 = ffs(sources1) - 1;
|
||||
return irq_0_31;
|
||||
return irq_0_31 + 32;
|
||||
},
|
||||
9 => {
|
||||
let sources2 = unsafe { self.read(PENDING_2) };
|
||||
let irq_32_63 = ffs(sources2) - 1;
|
||||
return irq_32_63 + 32;
|
||||
return irq_32_63 + 64;
|
||||
},
|
||||
num => {
|
||||
println!("unexpected irq pending in BASIC PENDING: {}", num);
|
||||
@@ -150,10 +188,97 @@ impl InterruptController for Bcm2835ArmInterruptController {
|
||||
}
|
||||
|
||||
fn irq_enable(&mut self, irq_num: u32) {
|
||||
|
||||
println!("bcm2835 enable {} {}", irq_num, irq_num & 0x1f);
|
||||
match irq_num {
|
||||
num @0..=31 => {
|
||||
let val = 1 << num;
|
||||
unsafe { self.write(ENABLE_0, val); }
|
||||
},
|
||||
num @32..=63 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(ENABLE_1, val); }
|
||||
},
|
||||
num @64..=95 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(ENABLE_2, val); }
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_disable(&mut self, irq_num: u32) {
|
||||
match irq_num {
|
||||
num @0..=31 => {
|
||||
let val = 1 << num;
|
||||
unsafe { self.write(DISABLE_0, val); }
|
||||
},
|
||||
num @32..=63 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(DISABLE_1, val); }
|
||||
},
|
||||
num @64..=95 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(DISABLE_2, val); }
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
|
||||
}
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize> {
|
||||
//assert interrupt-cells == 0x2
|
||||
let mut off: usize = 0;
|
||||
let mut i = 0;
|
||||
//assert interrupt-cells == 0x2
|
||||
for chunk in irq_data.chunks(2) {
|
||||
if i == idx {
|
||||
let bank = chunk[0] as usize;
|
||||
let irq = chunk[1] as usize;
|
||||
//TODO: check bank && irq
|
||||
let hwirq = bank << 5 | irq;
|
||||
off = hwirq + self.irq_range.0;
|
||||
return Ok(off);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
if hwirq > 95 {
|
||||
None
|
||||
} else {
|
||||
Some(self.irq_range.0 + hwirq as usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
|
||||
unsafe {
|
||||
let irq = self.irq_ack();
|
||||
if let Some(virq) = self.irq_to_virq(irq) && virq < 1024 {
|
||||
if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler {
|
||||
handler.irq_handler(virq as u32);
|
||||
}
|
||||
} else {
|
||||
println!("unexpected irq num {}", irq);
|
||||
}
|
||||
self.irq_eoi(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Bcm2835ArmInterruptController {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
|
||||
unsafe {
|
||||
let irq = self.irq_ack();
|
||||
if let Some(virq) = self.irq_to_virq(irq) && virq < 1024 {
|
||||
if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler {
|
||||
handler.irq_handler(virq as u32);
|
||||
}
|
||||
} else {
|
||||
println!("unexpected irq num {}", irq);
|
||||
}
|
||||
self.irq_eoi(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use core::{ptr::{read_volatile, write_volatile}, arch::asm};
|
||||
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{DeviceTree, Node};
|
||||
@@ -6,26 +6,26 @@ use fdt::{DeviceTree, Node};
|
||||
use crate::{device::io_mmap, init::device_tree::find_compatible_node};
|
||||
use syscall::{Result, error::{Error, EINVAL}};
|
||||
|
||||
use super::InterruptController;
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
static LOCAL_CONTROL: u32 = 0x000;
|
||||
static LOCAL_PRESCALER: u32 = 0x008;
|
||||
static LOCAL_GPU_ROUTING: u32 = 0x00C;
|
||||
static LOCAL_TIMER_INT_CONTROL0: u32 = 0x040;
|
||||
static LOCAL_IRQ_PENDING: u32 = 0x060;
|
||||
static LOCAL_FIQ_PENDING: u32 = 0x070;
|
||||
const LOCAL_CONTROL: u32 = 0x000;
|
||||
const LOCAL_PRESCALER: u32 = 0x008;
|
||||
const LOCAL_GPU_ROUTING: u32 = 0x00C;
|
||||
const LOCAL_TIMER_INT_CONTROL0: u32 = 0x040;
|
||||
const LOCAL_IRQ_PENDING: u32 = 0x060;
|
||||
const LOCAL_FIQ_PENDING: u32 = 0x070;
|
||||
|
||||
static LOCAL_IRQ_CNTPSIRQ: u32 = 0x0;
|
||||
static LOCAL_IRQ_CNTPNSIRQ: u32 = 0x1;
|
||||
static LOCAL_IRQ_CNTHPIRQ: u32 = 0x2;
|
||||
static LOCAL_IRQ_CNTVIRQ: u32 = 0x3;
|
||||
static LOCAL_IRQ_MAILBOX0: u32 = 0x4;
|
||||
static LOCAL_IRQ_MAILBOX1: u32 = 0x5;
|
||||
static LOCAL_IRQ_MAILBOX2: u32 = 0x6;
|
||||
static LOCAL_IRQ_MAILBOX3: u32 = 0x7;
|
||||
static LOCAL_IRQ_GPU_FAST: u32 = 0x8;
|
||||
static LOCAL_IRQ_PMU_FAST: u32 = 0x9;
|
||||
static LOCAL_IRQ_LAST: u32 = 0x9;
|
||||
const LOCAL_IRQ_CNTPSIRQ: u32 = 0x0;
|
||||
const LOCAL_IRQ_CNTPNSIRQ: u32 = 0x1;
|
||||
const LOCAL_IRQ_CNTHPIRQ: u32 = 0x2;
|
||||
const LOCAL_IRQ_CNTVIRQ: u32 = 0x3;
|
||||
const LOCAL_IRQ_MAILBOX0: u32 = 0x4;
|
||||
const LOCAL_IRQ_MAILBOX1: u32 = 0x5;
|
||||
const LOCAL_IRQ_MAILBOX2: u32 = 0x6;
|
||||
const LOCAL_IRQ_MAILBOX3: u32 = 0x7;
|
||||
const LOCAL_IRQ_GPU_FAST: u32 = 0x8;
|
||||
const LOCAL_IRQ_PMU_FAST: u32 = 0x9;
|
||||
const LOCAL_IRQ_LAST: u32 = LOCAL_IRQ_PMU_FAST;
|
||||
|
||||
#[inline(always)]
|
||||
fn ffs(num: u32) -> u32 {
|
||||
@@ -60,25 +60,21 @@ fn ffs(num: u32) -> u32 {
|
||||
|
||||
pub struct Bcm2836ArmInterruptController {
|
||||
pub address: usize,
|
||||
pub irq_range: (usize, usize),
|
||||
pub active_cpu: u32,
|
||||
}
|
||||
|
||||
|
||||
impl Bcm2836ArmInterruptController {
|
||||
pub fn new() -> Self {
|
||||
Bcm2836ArmInterruptController { address: 0 }
|
||||
Bcm2836ArmInterruptController { address: 0, irq_range: (0, 0), active_cpu: 0 }
|
||||
}
|
||||
pub fn parse(fdt: Option<&DeviceTree>) -> Result<(usize, usize)> {
|
||||
match fdt {
|
||||
//TODO: remove hard code for qemu-virt
|
||||
None => Err(Error::new(EINVAL)),
|
||||
Some(dtb) => {
|
||||
//TODO: try to parse dtb using stable library
|
||||
if let Some(node) = find_compatible_node(dtb, "brcm,bcm2836-l1-intc") {
|
||||
return Bcm2836ArmInterruptController::parse_inner(&node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize)> {
|
||||
//TODO: try to parse dtb using stable library
|
||||
if let Some(node) = find_compatible_node(fdt, "brcm,bcm2836-l1-intc") {
|
||||
return Bcm2836ArmInterruptController::parse_inner(&node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
fn parse_inner(node: &Node) -> Result<(usize, usize)> {
|
||||
@@ -97,8 +93,9 @@ impl Bcm2836ArmInterruptController {
|
||||
self.write(LOCAL_CONTROL, 0x0);
|
||||
self.write(LOCAL_PRESCALER, 0x8000_0000);
|
||||
|
||||
//routing all irq to core0
|
||||
self.write(LOCAL_GPU_ROUTING, 0x0);
|
||||
//routing all irq to core
|
||||
self.write(LOCAL_GPU_ROUTING, self.active_cpu);
|
||||
println!("routing all irq to core {}", self.active_cpu);
|
||||
println!("IRQ BCM2836 END");
|
||||
}
|
||||
|
||||
@@ -113,7 +110,7 @@ impl Bcm2836ArmInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController for Bcm2836ArmInterruptController {
|
||||
fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()> {
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>> {
|
||||
let (base, size) = match Bcm2836ArmInterruptController::parse(fdt) {
|
||||
Ok((a, b)) => (a, b),
|
||||
Err(_) => return Err(Error::new(EINVAL)),
|
||||
@@ -121,18 +118,37 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
unsafe {
|
||||
io_mmap(base, size);
|
||||
|
||||
self.address = base;
|
||||
self.address = base + crate::PHYS_OFFSET;
|
||||
let mut cpuid: usize = 0;
|
||||
asm!("mrs {}, mpidr_el1", out(reg) cpuid);
|
||||
self.active_cpu = cpuid as u32 & 0x3;
|
||||
|
||||
self.init();
|
||||
let idx = *irq_idx;
|
||||
let cnt = LOCAL_IRQ_LAST as usize;
|
||||
let mut i: usize = 0;
|
||||
//only support linear irq map now.
|
||||
while i < cnt && (idx + i < 1024) {
|
||||
irq_desc[idx + i].basic.ic_idx = ic_idx;
|
||||
irq_desc[idx + i].basic.ic_irq = i as u32;
|
||||
irq_desc[idx + i].basic.used = true;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
println!("bcm2836 irq_range = ({}, {})", idx, idx + cnt);
|
||||
self.irq_range = (idx, idx + cnt);
|
||||
*irq_idx = idx + cnt;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn irq_ack(&mut self) -> u32 {
|
||||
//TODO: support smp self.read(LOCAL_IRQ_PENDING + 4 * cpu)
|
||||
//assert cpu == 0
|
||||
let sources = unsafe { self.read(LOCAL_IRQ_PENDING) };
|
||||
let mut cpuid: usize = 0;
|
||||
unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); }
|
||||
let mut cpu = cpuid as u32 & 0x3;
|
||||
let sources: u32 = unsafe { self.read(LOCAL_IRQ_PENDING + 4 * cpu) };
|
||||
ffs(sources) - 1
|
||||
}
|
||||
|
||||
@@ -141,10 +157,64 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
}
|
||||
|
||||
fn irq_enable(&mut self, irq_num: u32) {
|
||||
|
||||
match irq_num {
|
||||
LOCAL_IRQ_CNTPNSIRQ => unsafe {
|
||||
let mut cpuid: usize = 0;
|
||||
unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); }
|
||||
let mut cpu = cpuid as u32 & 0x3;
|
||||
let mut reg_val = self.read(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu);
|
||||
reg_val |= 0x2;
|
||||
self.write(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu, reg_val);
|
||||
},
|
||||
LOCAL_IRQ_GPU_FAST => {
|
||||
//GPU IRQ always enable
|
||||
},
|
||||
_ => {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_disable(&mut self, irq_num: u32) {
|
||||
match irq_num {
|
||||
LOCAL_IRQ_CNTPNSIRQ => unsafe {
|
||||
let mut cpuid: usize = 0;
|
||||
unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); }
|
||||
let mut cpu = cpuid as u32 & 0x3;
|
||||
let mut reg_val = self.read(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu);
|
||||
reg_val &= !0x2;
|
||||
self.write(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu, reg_val);
|
||||
},
|
||||
LOCAL_IRQ_GPU_FAST => {
|
||||
//GPU IRQ always enable
|
||||
},
|
||||
_ => {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize> {
|
||||
let mut off: usize = 0;
|
||||
let mut i = 0;
|
||||
//assert interrupt-cells == 0x2
|
||||
for chunk in irq_data.chunks(2) {
|
||||
if i == idx {
|
||||
off = chunk[0] as usize + self.irq_range.0;
|
||||
return Ok(off);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
if hwirq > LOCAL_IRQ_LAST {
|
||||
None
|
||||
} else {
|
||||
Some(self.irq_range.0 + hwirq as usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +1,263 @@
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use alloc::{boxed::Box, vec::Vec, string::{String, ToString}};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use syscall::Result;
|
||||
use fdt::DeviceTree;
|
||||
|
||||
use crate::init::device_tree::travel_interrupt_ctrl;
|
||||
|
||||
mod gic;
|
||||
mod irq_bcm2835;
|
||||
mod irq_bcm2836;
|
||||
|
||||
pub const IRQ_TYPE_NONE: u32 = 0;
|
||||
pub const IRQ_TYPE_EDGE_RISING: u32 = 1;
|
||||
pub const IRQ_TYPE_EDGE_FALLING: u32 = 2;
|
||||
pub const IRQ_TYPE_EDGE: u32 = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; //both rising && failling
|
||||
pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4;
|
||||
pub const IRQ_TYPE_LEVEL_LOW: u32 = 8;
|
||||
|
||||
pub trait InterruptController {
|
||||
fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()>;
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>>;
|
||||
fn irq_ack(&mut self) -> u32;
|
||||
fn irq_eoi(&mut self, irq_num: u32);
|
||||
fn irq_enable(&mut self, irq_num: u32);
|
||||
fn irq_disable(&mut self, irq_num: u32);
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize>;
|
||||
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize>;
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
}
|
||||
|
||||
pub trait InterruptHandler {
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
}
|
||||
|
||||
pub struct IrqChipItem {
|
||||
pub compatible: String,
|
||||
pub phandle: u32,
|
||||
pub parent_phandle: Option<u32>,
|
||||
pub intr_cell_size: u32,
|
||||
pub parent: Option<usize>, //parent idx in chiplist
|
||||
pub childs: Vec<usize>, //child idx in chiplist
|
||||
pub interrupts: Vec<u32>,
|
||||
pub ic: Box<dyn InterruptController>,
|
||||
}
|
||||
|
||||
pub struct IrqChipList {
|
||||
pub chips: Vec<IrqChipItem>,
|
||||
pub root_phandle: u32,
|
||||
pub root_idx: usize,
|
||||
}
|
||||
|
||||
pub struct IrqDescItem {
|
||||
pub idx: usize,
|
||||
pub ic_idx: usize, //ic idx in irq chip list
|
||||
pub child_ic_idx: Option<usize>, //ic idx in irq chip list
|
||||
pub ic_irq: u32, //hwirq in ic
|
||||
pub used: bool,
|
||||
}
|
||||
|
||||
pub struct IrqDesc {
|
||||
pub basic: IrqDescItem,
|
||||
pub handler: Option<Box<dyn InterruptHandler>>,
|
||||
}
|
||||
|
||||
impl IrqChipList {
|
||||
fn init_inner1(&mut self, fdt: &fdt::DeviceTree) {
|
||||
let root_node = fdt.nodes().nth(0).unwrap();
|
||||
let mut idx = 0;
|
||||
let intr = root_node.properties().find(|p| p.name.contains("interrupt-parent")).unwrap();
|
||||
|
||||
let root_intr_parent = BE::read_u32(&intr.data);
|
||||
println!("root parent = 0x{:08x}", root_intr_parent);
|
||||
self.root_phandle = root_intr_parent;
|
||||
for node in fdt.nodes() {
|
||||
if node.properties().find(|p| p.name.contains("interrupt-controller")).is_some() {
|
||||
let compatible = node.properties().find(|p| p.name.contains("compatible")).unwrap();
|
||||
let phandle = node.properties().find(|p| p.name.contains("phandle")).unwrap();
|
||||
let intr_cells = node.properties().find(|p| p.name.contains("#interrupt-cells")).unwrap();
|
||||
let _intr = node.properties().find(|p| p.name.contains("interrupt-parent"));
|
||||
let _intr_data = node.properties().find(|p| p.name.contains("interrupts"));
|
||||
|
||||
let s = core::str::from_utf8(compatible.data).unwrap();
|
||||
println!("{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", node.name, s, BE::read_u32(intr_cells.data),
|
||||
BE::read_u32(phandle.data));
|
||||
let mut item = IrqChipItem {
|
||||
compatible: s.to_string(),
|
||||
phandle: BE::read_u32(phandle.data),
|
||||
parent_phandle: None,
|
||||
intr_cell_size: BE::read_u32(intr_cells.data),
|
||||
parent: None,
|
||||
childs: Vec::new(),
|
||||
interrupts: Vec::new(),
|
||||
ic: IrqChipCore::new_ic(&s).unwrap(),
|
||||
};
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
println!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data));
|
||||
item.parent_phandle = Some(BE::read_u32(intr.data));
|
||||
println!("interrupts begin:");
|
||||
for chunk in intr_data.data.chunks(4) {
|
||||
print!("0x{:08x}, ", BE::read_u32(chunk));
|
||||
item.interrupts.push(BE::read_u32(chunk));
|
||||
}
|
||||
println!("interrupts end");
|
||||
}
|
||||
}
|
||||
if item.phandle == root_intr_parent {
|
||||
self.root_idx = idx as usize;
|
||||
}
|
||||
|
||||
self.chips.push(item);
|
||||
|
||||
idx += 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_inner2(&mut self) {
|
||||
let mut x = 0;
|
||||
let mut y = 0;
|
||||
|
||||
while x < self.chips.len() {
|
||||
y = 0;
|
||||
while y < self.chips.len() {
|
||||
if x == y {
|
||||
y += 1;
|
||||
continue;
|
||||
}
|
||||
if let Some(pp) = self.chips[y].parent_phandle && pp == self.chips[x].phandle {
|
||||
self.chips[y].parent = Some(x);
|
||||
self.chips[x].childs.push(y);
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn init_inner3(&mut self, fdt: &fdt::DeviceTree, irq_desc: &mut [IrqDesc; 1024]) {
|
||||
//run init
|
||||
let mut queue = Vec::new();
|
||||
let mut irq_idx: usize = 0;
|
||||
queue.push(self.root_idx);
|
||||
while !queue.is_empty() {
|
||||
let cur_idx = queue.pop().unwrap();
|
||||
queue.extend_from_slice(&self.chips[cur_idx].childs);
|
||||
let virq = self.chips[cur_idx].ic.irq_init(fdt, irq_desc, cur_idx, &mut irq_idx);
|
||||
if let Ok(Some(virq)) = virq {
|
||||
irq_desc[virq].basic.child_ic_idx = Some(cur_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct IrqChipCore {
|
||||
//TODO: support multi level interrupt constrollers
|
||||
pub ic: Vec<Box<dyn InterruptController>>,
|
||||
pub ic_idx: usize,
|
||||
pub irq_chip_list: IrqChipList,
|
||||
pub handlers: [Option<Box<dyn InterruptHandler>>; 1024],
|
||||
pub irq_desc: [IrqDesc; 1024],
|
||||
}
|
||||
|
||||
impl IrqChipCore {
|
||||
pub fn irq_ack(&mut self) -> u32 {
|
||||
self.ic[self.ic_idx].irq_ack()
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx].ic.irq_ack()
|
||||
}
|
||||
|
||||
pub fn irq_eoi(&mut self, irq_num: u32) {
|
||||
self.ic[self.ic_idx].irq_eoi(irq_num)
|
||||
pub fn irq_eoi(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_eoi(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_enable(&mut self, irq_num: u32) {
|
||||
self.ic[self.ic_idx].irq_enable(irq_num)
|
||||
pub fn irq_enable(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_enable(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_disable(&mut self, irq_num: u32) {
|
||||
self.ic[self.ic_idx].irq_disable(irq_num)
|
||||
pub fn irq_disable(&mut self, virq: u32) {
|
||||
let irq_desc = &self.irq_desc[virq as usize];
|
||||
let ic_idx = irq_desc.basic.ic_idx;
|
||||
let hwirq = irq_desc.basic.ic_irq;
|
||||
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_disable(hwirq)
|
||||
}
|
||||
|
||||
pub fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx].ic.irq_to_virq(hwirq)
|
||||
}
|
||||
|
||||
pub fn init(&mut self, fdt: &DeviceTree) {
|
||||
for i in 0..1024 {
|
||||
self.irq_desc[i].basic.idx = i;
|
||||
}
|
||||
self.irq_chip_list.init_inner1(fdt);
|
||||
self.irq_chip_list.init_inner2();
|
||||
self.irq_chip_list.init_inner3(fdt, &mut self.irq_desc);
|
||||
|
||||
}
|
||||
|
||||
pub fn new_ic(ic_str: &str) -> Option<Box<dyn InterruptController>> {
|
||||
if ic_str.contains("arm,cortex-a15-gic") {
|
||||
Some(Box::new(gic::GenericInterruptController::new()))
|
||||
} else if ic_str.contains("brcm,bcm2836-l1-intc") {
|
||||
Some(Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new()))
|
||||
} else if ic_str.contains("brcm,bcm2836-armctrl-ic") {
|
||||
Some(Box::new(irq_bcm2835::Bcm2835ArmInterruptController::new()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const INIT_HANDLER: Option<Box<dyn InterruptHandler>> = None;
|
||||
const INIT_IRQ_DESC: IrqDesc = IrqDesc {
|
||||
basic: IrqDescItem {
|
||||
idx: 0,
|
||||
ic_idx: 0,
|
||||
ic_irq: 0,
|
||||
child_ic_idx: None,
|
||||
used: false,
|
||||
},
|
||||
handler: INIT_HANDLER,
|
||||
};
|
||||
pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
|
||||
ic: Vec::new(),
|
||||
ic_idx: 0,
|
||||
irq_chip_list: IrqChipList {
|
||||
chips: Vec::new(),
|
||||
root_phandle: 0,
|
||||
root_idx: 0,
|
||||
},
|
||||
handlers: [INIT_HANDLER; 1024],
|
||||
irq_desc: [INIT_IRQ_DESC; 1024],
|
||||
};
|
||||
|
||||
pub fn init(fdt: Option<&DeviceTree>) {
|
||||
|
||||
pub fn init(fdt: &DeviceTree) {
|
||||
travel_interrupt_ctrl(fdt);
|
||||
unsafe {
|
||||
let ic = Box::new(gic::GenericInterruptController::new());
|
||||
IRQ_CHIP.ic.push(ic);
|
||||
let ic = Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new());
|
||||
IRQ_CHIP.ic.push(ic);
|
||||
for ic in IRQ_CHIP.ic.iter_mut() {
|
||||
let _ = ic.irq_init(fdt);
|
||||
}
|
||||
IRQ_CHIP.init(fdt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_irq(irq: u32, handler: Box<dyn InterruptHandler>) {
|
||||
if irq >= 1024 {
|
||||
println!("irq {} exceed 1024!!!", {irq});
|
||||
pub fn register_irq(virq: u32, handler: Box<dyn InterruptHandler>) {
|
||||
if virq >= 1024 {
|
||||
println!("irq {} exceed 1024!!!", virq);
|
||||
return ;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if let Some(_) = IRQ_CHIP.handlers[irq as usize] {
|
||||
println!("irq {} has already been registered!", irq);
|
||||
if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq as usize].handler {
|
||||
println!("irq {} has already been registered!", virq);
|
||||
return ;
|
||||
}
|
||||
|
||||
IRQ_CHIP.handlers[irq as usize] = Some(handler);
|
||||
IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, PhysicalAddress, Page, PageFlags, VirtualAddress};
|
||||
use crate::dtb::DTB_BINARY;
|
||||
@@ -12,17 +14,16 @@ pub mod uart_pl011;
|
||||
pub unsafe fn init() {
|
||||
println!("IRQCHIP INIT");
|
||||
let data = DTB_BINARY.get().unwrap();
|
||||
if data.len() == 0 {
|
||||
irqchip::init(None);
|
||||
} else {
|
||||
let fdt = fdt::DeviceTree::new(data).unwrap();
|
||||
irqchip::init(Some(&fdt));
|
||||
}
|
||||
let fdt = fdt::DeviceTree::new(data).unwrap();
|
||||
irqchip::init(&fdt);
|
||||
println!("GIT INIT");
|
||||
generic_timer::init();
|
||||
}
|
||||
|
||||
pub unsafe fn init_noncore() {
|
||||
let mut daif: usize = 0;
|
||||
asm!("mrs {0}, daif", out(reg) daif);
|
||||
println!("daif = 0x{:08x}", daif);
|
||||
println!("SERIAL INIT");
|
||||
serial::init();
|
||||
println!("RTC INIT");
|
||||
|
||||
@@ -5,6 +5,10 @@ use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger};
|
||||
use crate::init::device_tree;
|
||||
|
||||
use super::irqchip::{register_irq, IRQ_CHIP, InterruptHandler};
|
||||
use crate::dtb::DTB_BINARY;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub static COM1: Mutex<Option<SerialPort>> = Mutex::new(None);
|
||||
|
||||
@@ -39,10 +43,37 @@ pub unsafe fn init_early(dtb_base: usize, dtb_size: usize) {
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
println!("test 1");
|
||||
if let Some(ref mut serial_port) = *COM1.lock() {
|
||||
serial_port.receive();
|
||||
serial_port.init(true);
|
||||
register_irq(33, Box::new(Com1Irq {}));
|
||||
// Enable interrupt at GIC distributor
|
||||
unsafe { IRQ_CHIP.irq_enable(33); }
|
||||
}
|
||||
println!("test 2");
|
||||
let data = DTB_BINARY.get().unwrap();
|
||||
let fdt = fdt::DeviceTree::new(data).unwrap();
|
||||
if let Some(node) = find_compatible_node(&fdt, "arm,pl011") {
|
||||
let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap();
|
||||
let mut intr_data = Vec::new();
|
||||
for chunk in interrupts.data.chunks(4) {
|
||||
let val = BE::read_u32(chunk);
|
||||
intr_data.push(val);
|
||||
}
|
||||
let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx;
|
||||
if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) {
|
||||
let phandle = BE::read_u32(interrupt_parent.data);
|
||||
let mut i = 0;
|
||||
while i < IRQ_CHIP.irq_chip_list.chips.len() {
|
||||
let item = &IRQ_CHIP.irq_chip_list.chips[i];
|
||||
if item.phandle == phandle {
|
||||
ic_idx = i;
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 0).unwrap();
|
||||
println!("serial_port virq = {}", virq);
|
||||
register_irq(virq as u32, Box::new(Com1Irq {}));
|
||||
IRQ_CHIP.irq_enable(virq as u32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,37 @@ pub fn root_cell_sz(dt: &fdt::DeviceTree) -> Option<(u32, u32)> {
|
||||
Some((BE::read_u32(&size_cells.data), BE::read_u32(&size_cells.data)))
|
||||
}
|
||||
|
||||
pub fn travel_interrupt_ctrl(fdt: &fdt::DeviceTree) {
|
||||
let root_node = fdt.nodes().nth(0).unwrap();
|
||||
let intr = root_node.properties().find(|p| p.name.contains("interrupt-parent")).unwrap();
|
||||
|
||||
let root_intr_parent = BE::read_u32(&intr.data);
|
||||
println!("root parent = 0x{:08x}", root_intr_parent);
|
||||
for node in fdt.nodes() {
|
||||
if node.properties().find(|p| p.name.contains("interrupt-controller")).is_some() {
|
||||
let compatible = node.properties().find(|p| p.name.contains("compatible")).unwrap();
|
||||
let phandle = node.properties().find(|p| p.name.contains("phandle")).unwrap();
|
||||
let intr_cells = node.properties().find(|p| p.name.contains("#interrupt-cells")).unwrap();
|
||||
let _intr = node.properties().find(|p| p.name.contains("interrupt-parent"));
|
||||
let _intr_data = node.properties().find(|p| p.name.contains("interrupts"));
|
||||
|
||||
let s = core::str::from_utf8(compatible.data).unwrap();
|
||||
println!("{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", node.name, s, BE::read_u32(intr_cells.data),
|
||||
BE::read_u32(phandle.data));
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
println!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data));
|
||||
println!("interrupts begin:");
|
||||
for chunk in intr_data.data.chunks(4) {
|
||||
print!("0x{:08x}, ", BE::read_u32(chunk));
|
||||
}
|
||||
println!("interrupts end");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usize, ranges: &mut [(usize, usize); 10]) -> usize {
|
||||
|
||||
let (memory_node, _memory_cells) = dt.find_node("/memory").unwrap();
|
||||
|
||||
@@ -1,34 +1,42 @@
|
||||
use crate::context;
|
||||
use crate::context::timeout;
|
||||
//use crate::device::generic_timer::{GENTIMER};
|
||||
use crate::device::irqchip::IRQ_CHIP;
|
||||
use crate::device::serial::{COM1};
|
||||
use crate::time;
|
||||
use crate::device::serial::COM1;
|
||||
|
||||
use crate::{exception_stack};
|
||||
pub struct IrqDesc {
|
||||
pub virq: u32,
|
||||
pub hwirq: u32,
|
||||
}
|
||||
|
||||
exception_stack!(irq_at_el0, |stack| {
|
||||
let irq = IRQ_CHIP.irq_ack();
|
||||
if irq >= 1024 {
|
||||
println!("unexpected irq num {}", irq);
|
||||
} else {
|
||||
if let Some(handler) = &mut IRQ_CHIP.handlers[irq as usize] {
|
||||
handler.irq_handler(irq);
|
||||
//println!("el0 irq num {}", irq);
|
||||
if let Some(virq) = IRQ_CHIP.irq_to_virq(irq) && virq < 1024 {
|
||||
if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler {
|
||||
handler.irq_handler(virq as u32);
|
||||
} else if let Some(ic_idx) = IRQ_CHIP.irq_desc[virq].basic.child_ic_idx {
|
||||
IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_handler(virq as u32);
|
||||
}
|
||||
} else {
|
||||
println!("unexpected irq num {}", irq);
|
||||
}
|
||||
});
|
||||
|
||||
exception_stack!(irq_at_el1, |stack| {
|
||||
let irq = IRQ_CHIP.irq_ack();
|
||||
if irq >= 1024 {
|
||||
println!("unexpected irq num {}", irq);
|
||||
} else {
|
||||
if let Some(handler) = &mut IRQ_CHIP.handlers[irq as usize] {
|
||||
handler.irq_handler(irq);
|
||||
//println!("el1 irq num {}", irq);
|
||||
if let Some(virq) = IRQ_CHIP.irq_to_virq(irq) && virq < 1024 {
|
||||
if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler {
|
||||
handler.irq_handler(virq as u32);
|
||||
} else if let Some(ic_idx) = IRQ_CHIP.irq_desc[virq].basic.child_ic_idx {
|
||||
IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_handler(virq as u32);
|
||||
}
|
||||
} else {
|
||||
println!("unexpected irq num {}", irq);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//TODO
|
||||
pub unsafe fn trigger(irq: u32) {
|
||||
extern {
|
||||
fn irq_trigger(irq: u32);
|
||||
|
||||
Reference in New Issue
Block a user