singrdk/base/Kernel/Singularity.Hal.Omap3430/Pic.cs

486 lines
19 KiB
C#
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Pic.cs
//
#define DEBUG_INTERRUPTS
#define DEBUG_DISPATCH_IO
#define PIC_DEBUG
using Microsoft.Singularity.Io;
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.Singularity.Configuration;
using Microsoft.Singularity.Isal.Arm;
namespace Microsoft.Singularity.Hal
{
// declare resources for the kernel manifest
[DriverCategory]
[Signature("/arm/ti/3430/INTCPS")]
public sealed class PicResources : DriverCategoryDeclaration
{
[IoMemoryRange(0, Default = 0x48200000, Length = 0x1000)]
internal readonly IoMemoryRange registers;
// CTR will create the rest of this class:
public PicResources(IoConfig config)
{
// dynamic resources
registers = (IoMemoryRange)config.DynamicRanges[0];
}
}
[CLSCompliant(false)]
public sealed class Pic : HalPic
{
// size of register block
const int PicRegisterSize = 0x00000280; // size of registers in block
// registers
const uint INTCPS_REVISION = 0x00000000; // INTCPS block revision
const uint INTCPS_SYSCONFIG = 0x00000010; // configuration
const uint INTCPS_SYSSTATUS = 0x00000014; // status
const uint INTCPS_SIR_IRQ = 0x00000040; // IRQ source interrupt
const uint INTCPS_SIR_FIQ = 0x00000044; // FIQ source interrupt
const uint INTCPS_CONTROL = 0x00000048; // control
const uint INTCPS_PROTECTION = 0x0000004c; // pic access control
const uint INTCPS_IDLE = 0x00000050; // clock idling
const uint INTCPS_IRQ_PRIORITY = 0x00000060; // IRQ priority level
const uint INTCPS_FIQ_PRIORITY = 0x00000064; // FIQ priority level
const uint INTCPS_THRESHHOLD = 0x00000068; // priority threshold control
const uint INTCPS_ITR = 0x00000080; // raw interrupt status vector
const uint INTCPS_MIR = 0x00000084; // interrupt mask vector
const uint INTCPS_MIR_CLEAR = 0x00000088; // clear interrupt mask vector
const uint INTCPS_MIR_SET = 0x0000008c; // set interrupt mask vector
const uint INTCPS_ISR_SET = 0x00000090; // assert software interrupt vector
const uint INTCPS_ISR_CLEAR = 0x00000094; // clear software interrupt vector
const uint INTCPS_PENDING_IRQ = 0x00000098; // pending (masked) IRQ interrupt vector
const uint INTCPS_PENDING_FIQ = 0x0000009c; // pending (masked) FIQ interrupt vector
const uint INTCPS_ILR_Base = 0x00000100; // interrupt priority & fast/slow control
const uint INTCPS_ILR_Offset = 0x00000004; // interrupt priority & fast/slow control
// source interrupt fields
const uint INTCPS_SIR_IRQ_ACTIVEIRQ_Mask = 0x0000007f; // active IRQ number
const uint INTCPS_SIR_FIQ_ACTIVEFIQ_Mask = 0x0000007f; // active FIQ number
// interrupt priority fields
const uint INTCPS_IRQ_PRIORITY_Mask = 0x0000003f; // current irq priority
const uint INTCPS_FIQ_PRIORITY_Mask = 0x0000003f; // current fiq priority
// interrupt level/routing fields
const uint INTCPS_ILR_FIQNIRQ = 0x00000001; // FIQ/IRQ routing
const uint INTCPS_ILR_PRIORITY_Mask = 0x0000000d; // interrupt priority
const int INTCPS_ILR_PRIORITY_Shift = 0x00000002; // interrupt priority
// registers
private IoMappedPort intcps_revision; // INTCPS block revision
private IoMappedPort intcps_sysconfig; // configuration
private IoMappedPort intcps_sysstatus; // status
private IoMappedPort intcps_sir_irq; // IRQ source interrupt
private IoMappedPort intcps_sir_fiq; // FIQ source interrupt
private IoMappedPort intcps_control; // control
private IoMappedPort intcps_protection; // pic access control
private IoMappedPort intcps_idle; // clock idling
private IoMappedPort intcps_irq_priority; // IRQ priority level
private IoMappedPort intcps_fiq_priority; // FIQ priority level
private IoMappedPort intcps_threshhold; // priority threshold control
private IoMappedPort[] intcps_itr; // raw interrupt status vector
private IoMappedPort[] intcps_mir; // interrupt mask vector
private IoMappedPort[] intcps_mir_clear; // clear interrupt mask vector
private IoMappedPort[] intcps_mir_set; // set interrupt mask vector
private IoMappedPort[] intcps_isr_set; // assert software interrupt vector
private IoMappedPort[] intcps_isr_clear; // clear software interrupt vector
private IoMappedPort[] intcps_pending_irq; // pending (masked) IRQ interrupt vector
private IoMappedPort[] intcps_pending_fiq; // pending (masked) FIQ interrupt vector
private IoMappedPort intcps_ilr; // interrupt level/routing
// constants for PIC interrupt vectors
const byte INTCPS_Vectors = 0x60; // count of OMAP3430 interrupt vectors
const byte INTCPS_Subvector_Size = 0x20; // size of sub-vectors
private uint irqMask0; // copy of interrupt mask
private uint irqMask1; // copy of interrupt mask
private uint irqMask2; // copy of interrupt mask
internal Pic(PnpConfig config)
{
PicResources pr = new PicResources(config);
IoMemoryRange range = pr.registers;
IoMemory regs = range.MemoryAtOffset(0, PicRegisterSize, Access.ReadWrite);
intcps_revision = regs.MappedPortAtOffset(INTCPS_REVISION, 4, Access.Read);
intcps_sysconfig = regs.MappedPortAtOffset(INTCPS_SYSCONFIG, 4, Access.ReadWrite);
intcps_sysstatus = regs.MappedPortAtOffset(INTCPS_SYSSTATUS, 4, Access.Read);
intcps_sir_irq = regs.MappedPortAtOffset(INTCPS_SIR_IRQ, 4, Access.Read);
intcps_sir_fiq = regs.MappedPortAtOffset(INTCPS_SIR_FIQ, 4, Access.Read);
intcps_control = regs.MappedPortAtOffset(INTCPS_CONTROL, 4, Access.ReadWrite);
intcps_protection = regs.MappedPortAtOffset(INTCPS_PROTECTION, 4, Access.ReadWrite);
intcps_idle = regs.MappedPortAtOffset(INTCPS_IDLE, 4, Access.ReadWrite);
intcps_irq_priority = regs.MappedPortAtOffset(INTCPS_IRQ_PRIORITY, 4, Access.ReadWrite);
intcps_fiq_priority = regs.MappedPortAtOffset(INTCPS_FIQ_PRIORITY, 4, Access.ReadWrite);
intcps_threshhold = regs.MappedPortAtOffset(INTCPS_THRESHHOLD, 4, Access.ReadWrite);
intcps_itr = CreatePortVector(regs, INTCPS_ITR, Access.Read);
intcps_mir = CreatePortVector(regs, INTCPS_MIR, Access.ReadWrite);
intcps_mir_clear = CreatePortVector(regs, INTCPS_MIR_CLEAR, Access.Write);
intcps_mir_set = CreatePortVector(regs, INTCPS_MIR_SET, Access.Write);
intcps_isr_set = CreatePortVector(regs, INTCPS_ISR_SET, Access.ReadWrite);
intcps_isr_clear = CreatePortVector(regs, INTCPS_ISR_CLEAR, Access.Write);
intcps_pending_irq = CreatePortVector(regs, INTCPS_PENDING_IRQ, Access.Read);
intcps_pending_fiq = CreatePortVector(regs, INTCPS_PENDING_FIQ, Access.Read);
intcps_ilr = regs.MappedPortAtOffset(
INTCPS_ILR_Base,
INTCPS_ILR_Offset * INTCPS_Vectors,
Access.ReadWrite
);
}
private static IoMappedPort[] CreatePortVector(IoMemory regs, uint offset, Access access)
{
return new IoMappedPort[3] {
regs.MappedPortAtOffset(offset + 0x00, 4, access),
regs.MappedPortAtOffset(offset + 0x20, 4, access),
regs.MappedPortAtOffset(offset + 0x40, 4, access)
};
}
public void Initialize()
{
DebugStub.WriteLine("Pic.Initializing IRQs");
// mask all interrupts
MaskAll();
// clear all pending interrupts
intcps_isr_clear[0].Write32(0xffffffff);
intcps_isr_clear[1].Write32(0xffffffff);
intcps_isr_clear[2].Write32(0xffffffff);
}
public void Finalize()
{
UnmaskAll();
}
[NoHeapAllocation]
public override byte InterruptToIrq(byte interrupt)
{
DebugStub.WriteLine("Pic.InterruptToIrq({0})", __arglist(interrupt));
// hack - all h/w interrupts on ARM are routed through a common vector
DebugStub.Assert((interrupt == ExceptionVector.Fiq) ||
(interrupt == ExceptionVector.Irq));
IoResult result = IoResult.Success;
if (interrupt == ExceptionVector.Fiq) {
// read currently active FIQ
ushort sir = intcps_sir_fiq.Read16NoThrow(ref result);
return (byte)(sir & INTCPS_SIR_FIQ_ACTIVEFIQ_Mask);
}
else { // if (interrupt == ExceptionVector.Irq)
// read currently active IRQ
ushort sir = intcps_sir_irq.Read16NoThrow(ref result);
return (byte)(sir & INTCPS_SIR_IRQ_ACTIVEIRQ_Mask);
}
}
[NoHeapAllocation]
public override byte IrqToInterrupt(byte irq)
{
DebugStub.WriteLine("Pic.IrqToInterrupt({0})", __arglist(irq));
// range check
DebugStub.Assert(irq < INTCPS_Vectors);
// check where the interrupt is routed: IRQ or FIQ
IoResult result = IoResult.Success;
uint ilr = intcps_ilr.Read32NoThrow(irq * INTCPS_ILR_Offset, ref result);
if ((ilr & INTCPS_ILR_FIQNIRQ) != 0) {
return (byte)ExceptionVector.Fiq;
}
else {
return (byte)ExceptionVector.Irq;
}
}
public override byte MaximumIrq
{
[NoHeapAllocation]
get { return INTCPS_Vectors - 1; }
}
[System.Diagnostics.Conditional("PIC_DEBUG")]
[NoHeapAllocation]
private void DumpBits(String label, IoMappedPort[] regs)
{
IoResult result = IoResult.Success;
uint v0 = regs[0].Read32NoThrow(ref result);
uint v1 = regs[1].Read32NoThrow(ref result);
uint v2 = regs[2].Read32NoThrow(ref result);
DebugStub.WriteLine(label, __arglist(v0, v1, v2));
}
[System.Diagnostics.Conditional("PIC_DEBUG")]
[NoHeapAllocation]
private void DumpRegisters()
{
IoResult result = IoResult.Success;
ushort currentIrqNumber = (ushort)(intcps_sir_irq.Read16NoThrow(ref result)
& INTCPS_SIR_IRQ_ACTIVEIRQ_Mask);
ushort currentIrqPriority = (ushort)(intcps_irq_priority.Read16NoThrow(ref result)
& (ushort)INTCPS_IRQ_PRIORITY_Mask);
DebugStub.WriteLine("PIC Current IRQ: {0:x4} Priority: {0:x4}",
__arglist(currentIrqNumber, currentIrqPriority));
ushort currentFiqNumber = (ushort)(intcps_sir_fiq.Read16NoThrow(ref result)
& INTCPS_SIR_FIQ_ACTIVEFIQ_Mask);
ushort currentFiqPriority = (ushort)(intcps_fiq_priority.Read16NoThrow(ref result)
& INTCPS_FIQ_PRIORITY_Mask);
DebugStub.WriteLine("PIC Current FIQ: {0:x4} Priority: {0:x4}",
__arglist(currentFiqNumber, currentFiqPriority));
DumpBits("PIC raw interrupt status: {2:x8}{1:x8}{0:x8}", intcps_itr);
DumpBits("PIC interrupt mask: {2:x8}{1:x8}{0:x8}", intcps_mir);
DumpBits("PIC software interrupts: {2:x8}{1:x8}{0:x8}", intcps_isr_set);
DumpBits("PIC pending IRQs: {2:x8}{1:x8}{0:x8}", intcps_pending_irq);
DumpBits("PIC pending FIQs: {2:x8}{1:x8}{0:x8}", intcps_pending_fiq);
for (uint i = 0; i < INTCPS_Vectors; ++i) {
uint ilr = intcps_ilr.Read32NoThrow(i * INTCPS_ILR_Offset, ref result);
string interruptType = ((ilr & INTCPS_ILR_FIQNIRQ) != 0) ? "fiq" : "irq";
byte priority = (byte)((ilr & INTCPS_ILR_PRIORITY_Mask)
>> INTCPS_ILR_PRIORITY_Shift);
DebugStub.WriteLine("PIC ILR[{0}]: {1} Priority: {2:x2}",
__arglist(i, interruptType, priority));
}
DebugStub.Assert(IoResult.Success == result);
}
[NoHeapAllocation]
public override void ClearInterrupt(byte interrupt)
{
byte irq = InterruptToIrq(interrupt);
Mask(irq);
AckIrq(irq);
Unmask(irq);
#if DEBUG_INTERRUPTS
DebugStub.WriteLine("pic.ClearInterrupt({2:x8}{1:x8}{0:x8})",
__arglist(irqMask0, irqMask1, irqMask2));
#endif
}
[NoHeapAllocation]
public override void AckIrq(byte irq)
{
DebugStub.Assert(Processor.InterruptsDisabled());
#if PIC_DEBUG
DumpRegisters();
#endif
// Mark the IRQ as activated and mask it
#if DEBUG_INTERRUPTS
DebugStub.WriteLine("Int{0:x2} Acked, Mask={3:x8}{2:x8}{1:x8}",
__arglist(irq, irqMask0, irqMask1, irqMask2));
#endif
// Quiet the interrupt controller.
IoResult result = IoResult.Success;
uint n = irq / 32u;
uint bit = 1u << (irq % 32);
if (n < intcps_isr_clear.Length) {
intcps_isr_clear[n].Write32NoThrow(bit, ref result);
}
DebugStub.Assert(IoResult.Success == result);
#if PIC_DEBUG
DumpRegisters();
#endif
}
[NoHeapAllocation]
public override void EnableIrq(byte irq)
{
if (irq >= INTCPS_Vectors) {
DebugStub.Break();
// throw new OverflowException
// (String.Format("irq {0} out of range.", irq));
}
#if DEBUG_INTERRUPTS
DebugStub.WriteLine("Int{0:x2} Enable, Mask={3:x8}{2:x8}{1:x8}",
__arglist(irq, irqMask0, irqMask1, irqMask2));
#endif
bool saved = Processor.DisableInterrupts();
try {
Unmask(irq);
#if PIC_DEBUG
DumpRegisters();
#endif
}
finally {
Processor.RestoreInterrupts(saved);
}
}
[NoHeapAllocation]
public override void DisableIrq(byte irq)
{
if (irq >= INTCPS_Vectors) {
DebugStub.Break();
// throw new OverflowException
// (String.Format("irq {0} out of range.", irq));
}
#if DEBUG_INTERRUPTS
DebugStub.WriteLine("Int{0:x2} Disable", __arglist(irq));
#endif
bool saved = Processor.DisableInterrupts();
try {
Mask(irq);
#if PIC_DEBUG
DumpRegisters();
#endif
}
finally {
Processor.RestoreInterrupts(saved);
}
}
//////////////////////////////////////////////////////////////////////
//
//
[NoHeapAllocation]
private void Mask(byte irq)
{
DebugStub.Assert(Processor.InterruptsDisabled());
uint n = irq / 32u;
uint bit = 1u << (irq % 32);
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("PIC.Mask({0}) => {1:x8}", __arglist(irq, bit));
#endif
uint mask = GetMaskWord(n);
if ((mask & bit) == 0) {
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("-- Mask IRQs [{0}: old={1:x8} new={2:x8}",
__arglist(n, mask, mask | bit));
#endif
IoResult result = IoResult.Success;
intcps_mir_set[n].Write32NoThrow(bit, ref result);
DebugStub.Assert(IoResult.Success == result);
SetMaskWord(n, mask | bit);
#if PIC_DEBUG
DumpBits("-- PIC interrupt mask: {2:x8}{1:x8}{0:x8}", intcps_mir);
#endif
}
}
[NoHeapAllocation]
private void Unmask(byte irq)
{
DebugStub.Assert(Processor.InterruptsDisabled());
uint n = irq / 32u;
uint bit = 1u << (irq % 32);
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("PIC.Unmask({0}) => {1:x8}", __arglist(irq, bit));
#endif
uint mask = GetMaskWord(n);
if ((mask & bit) != 0) {
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("-- Unmask IRQs [{0}: old={1:x8} new={2:x8}",
__arglist(n, mask, mask & ~bit));
#endif
#if false // Enable this to set interrupt without hardware.
IoResult result = IoResult.Success;
intcps_mir_clear[n].Write32NoThrow(bit, ref result);
intcps_isr_set[n].Write32NoThrow(bit, ref result);
DebugStub.Assert(IoResult.Success == result);
#endif
SetMaskWord(n, mask & ~bit);
#if PIC_DEBUG
DumpBits("-- PIC interrupt mask: {2:x8}{1:x8}{0:x8}", intcps_mir);
#endif
}
}
[NoHeapAllocation]
public bool IrqMasked(byte irq)
{
uint n = irq / 32u;
uint bit = 1u << (irq % 32);
if (irq >= INTCPS_Vectors) {
return true;
}
return ((GetMaskWord(n) & bit) != 0);
}
[NoHeapAllocation]
private uint GetMaskWord(uint n)
{
switch (n) {
case 0: return irqMask0;
case 1: return irqMask1;
case 2: return irqMask2;
}
return 0;
}
[NoHeapAllocation]
private void SetMaskWord(uint n, uint value)
{
switch (n) {
case 0: irqMask0 = value; break;
case 1: irqMask1 = value; break;
case 2: irqMask2 = value; break;
}
}
private void MaskAll()
{
DebugStub.Assert(Processor.InterruptsDisabled());
for (int i = 0; i < intcps_mir_set.Length; i++) {
intcps_mir_set[i].Write32(0xffffffff);
}
irqMask0 = irqMask1 = irqMask2 = 0xffffffff;
}
private void UnmaskAll()
{
DebugStub.Assert(Processor.InterruptsDisabled());
for (int i = 0; i < intcps_mir_clear.Length; i++) {
intcps_mir_clear[i].Write32(0xffffffff);
}
irqMask0 = irqMask1 = irqMask2 = 0x0;
}
}
}