mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-11-16 12:34:45 +00:00
- Add support to the BSP to enable irq-generic management - Update the powerpc shared irq code to support irq-generic. This is an opt in option for existing powerpc bsps. This change should be simpler now - Fix a number of issues in ISA IRQ controller handling by porting fixes from the i386 (PC) BSP Closes #4247 Closes #4248
232 lines
7.0 KiB
C
232 lines
7.0 KiB
C
/*
|
|
* This file contains the implementation of the function described in irq.h
|
|
* related to Intel 8259 Programmable Interrupt controller.
|
|
*
|
|
* Copyright (C) 1998, 1999 valette@crf.canon.fr
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*/
|
|
|
|
#include <bsp.h>
|
|
#include <bsp/irq.h>
|
|
|
|
#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
|
|
#define PIC_EOI 0x20 ///< Generic End of Interrupt (EOI)
|
|
|
|
/* Operation control word type 3. Bit 3 (0x08) must be set. Even address. */
|
|
#define PIC_OCW3_RIS 0x01 /* 1 = read IS, 0 = read IR */
|
|
#define PIC_OCW3_RR 0x02 /* register read */
|
|
#define PIC_OCW3_P 0x04 /* poll mode command */
|
|
/* 0x08 must be 1 to select OCW3 vs OCW2 */
|
|
#define PIC_OCW3_SEL 0x08 /* must be 1 */
|
|
/* 0x10 must be 0 to select OCW3 vs ICW1 */
|
|
#define PIC_OCW3_SMM 0x20 /* special mode mask */
|
|
#define PIC_OCW3_ESMM 0x40 /* enable SMM */
|
|
|
|
/*-------------------------------------------------------------------------+
|
|
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
|
|
+--------------------------------------------------------------------------*/
|
|
/*
|
|
* lower byte is interrupt mask on the master PIC.
|
|
* while upper bits are interrupt on the slave PIC.
|
|
*/
|
|
static rtems_i8259_masks i8259s_imr_cache = 0xFFFB;
|
|
static rtems_i8259_masks i8259s_in_progress = 0;
|
|
|
|
static inline
|
|
void BSP_i8259s_irq_update_master_imr( void )
|
|
{
|
|
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
|
|
outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
|
|
}
|
|
|
|
static inline
|
|
void BSP_i8259s_irq_update_slave_imr( void )
|
|
{
|
|
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
|
|
outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
|
|
}
|
|
|
|
/*
|
|
* Is the IRQ valid?
|
|
*/
|
|
static inline bool BSP_i8259s_irq_valid(const rtems_irq_number irqLine)
|
|
{
|
|
return ((int)irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) &&
|
|
((int)irqLine <= BSP_ISA_IRQ_MAX_OFFSET);
|
|
}
|
|
|
|
/*
|
|
* Read the IRR register. The default.
|
|
*/
|
|
static inline uint8_t BSP_i8259s_irq_int_request_reg(uint32_t ioport)
|
|
{
|
|
uint8_t isr;
|
|
inport_byte(ioport, isr);
|
|
return isr;
|
|
}
|
|
|
|
/*
|
|
* Read the ISR register. Keep the default of the IRR.
|
|
*/
|
|
static inline uint8_t BSP_i8259s_irq_in_service_reg(uint32_t ioport)
|
|
{
|
|
uint8_t isr;
|
|
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
|
|
inport_byte(ioport, isr);
|
|
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
|
|
return isr;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------+
|
|
| Function: BSP_irq_disable_at_i8259s
|
|
| Description: Mask IRQ line in appropriate PIC chip.
|
|
| Global Variables: i8259s_imr_cache, i8259s_in_progress
|
|
| Arguments: vector_offset - number of IRQ line to mask.
|
|
| Returns: 0 is OK.
|
|
+--------------------------------------------------------------------------*/
|
|
int BSP_irq_disable_at_i8259s(const rtems_irq_number irqLine)
|
|
{
|
|
unsigned short mask;
|
|
rtems_interrupt_level level;
|
|
|
|
if (!BSP_i8259s_irq_valid(irqLine))
|
|
return -1;
|
|
|
|
rtems_interrupt_disable(level);
|
|
|
|
mask = 1 << irqLine;
|
|
i8259s_imr_cache |= mask;
|
|
|
|
if (irqLine < 8)
|
|
{
|
|
BSP_i8259s_irq_update_master_imr();
|
|
}
|
|
else
|
|
{
|
|
BSP_i8259s_irq_update_slave_imr();
|
|
}
|
|
|
|
rtems_interrupt_enable(level);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------+
|
|
| Function: BSP_irq_enable_at_i8259s
|
|
| Description: Unmask IRQ line in appropriate PIC chip.
|
|
| Global Variables: i8259s_imr_cache, i8259s_in_progress
|
|
| Arguments: irqLine - number of IRQ line to mask.
|
|
| Returns: Nothing.
|
|
+--------------------------------------------------------------------------*/
|
|
int BSP_irq_enable_at_i8259s(const rtems_irq_number irqLine)
|
|
{
|
|
rtems_interrupt_level level;
|
|
unsigned short mask;
|
|
uint8_t isr;
|
|
uint8_t irr;
|
|
|
|
if (!BSP_i8259s_irq_valid(irqLine))
|
|
return 1;
|
|
|
|
rtems_interrupt_disable(level);
|
|
|
|
mask = 1 << irqLine;
|
|
i8259s_imr_cache &= ~mask;
|
|
|
|
if (irqLine < 8)
|
|
{
|
|
isr = BSP_i8259s_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
|
|
irr = BSP_i8259s_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
|
|
BSP_i8259s_irq_update_master_imr();
|
|
}
|
|
else
|
|
{
|
|
isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
|
irr = BSP_i8259s_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
|
BSP_i8259s_irq_update_slave_imr();
|
|
}
|
|
|
|
rtems_interrupt_enable(level);
|
|
|
|
return 0;
|
|
} /* mask_irq */
|
|
|
|
int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine)
|
|
{
|
|
unsigned short mask;
|
|
|
|
if (!BSP_i8259s_irq_valid(irqLine))
|
|
return 1;
|
|
|
|
mask = (1 << irqLine);
|
|
return (~(i8259s_imr_cache & mask));
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------+
|
|
| Function: BSP_irq_ack_at_i8259s
|
|
| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
|
|
| Global Variables: None.
|
|
| Arguments: irqLine - number of IRQ line to acknowledge.
|
|
| Returns: Nothing.
|
|
+--------------------------------------------------------------------------*/
|
|
int BSP_irq_ack_at_i8259s(const rtems_irq_number irqLine)
|
|
{
|
|
uint8_t slave_isr = 0;
|
|
|
|
if (irqLine >= 8) {
|
|
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
|
|
slave_isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
|
}
|
|
|
|
/*
|
|
* Only issue the EOI to the master if there are no more interrupts in
|
|
* service for the slave. i8259a data sheet page 18, The Special Fully Nested
|
|
* Mode, b.
|
|
*/
|
|
if (slave_isr == 0)
|
|
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
|
|
|
|
return 0;
|
|
|
|
} /* ackIRQ */
|
|
|
|
unsigned short BSP_irq_suspend_i8259s(unsigned short mask)
|
|
{
|
|
unsigned short in_progress_save = i8259s_in_progress;
|
|
i8259s_in_progress |= mask;
|
|
BSP_i8259s_irq_update_master_imr();
|
|
BSP_i8259s_irq_update_slave_imr();
|
|
return in_progress_save;
|
|
}
|
|
|
|
void BSP_irq_resume_i8259s(unsigned short in_progress_save)
|
|
{
|
|
i8259s_in_progress = in_progress_save;
|
|
BSP_i8259s_irq_update_master_imr();
|
|
BSP_i8259s_irq_update_slave_imr();
|
|
}
|
|
|
|
void BSP_i8259s_init(void)
|
|
{
|
|
/*
|
|
* Always mask at least current interrupt to prevent re-entrance
|
|
*/
|
|
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
|
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */
|
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x04);/* edge tiggered, Cascade (slave) on IRQ2 */
|
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x01);/* Select 8086 mode */
|
|
outport_byte(PIC_MASTER_IMR_IO_PORT, 0xFB); /* Mask all except cascade */
|
|
/*
|
|
* init slave interrupt controller
|
|
*/
|
|
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, 0x11); /* Start init sequence */
|
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x08);/* Vector base = 8 */
|
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x02);/* edge triggered, Cascade (slave) on IRQ2 */
|
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x01); /* Select 8086 mode */
|
|
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0xFF); /* Mask all */
|
|
|
|
}
|