diff options
Diffstat (limited to 'c/src/lib/libbsp/mips/shared/irq/i8259.c')
-rw-r--r-- | c/src/lib/libbsp/mips/shared/irq/i8259.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/mips/shared/irq/i8259.c b/c/src/lib/libbsp/mips/shared/irq/i8259.c new file mode 100644 index 0000000000..df0a2e4e2f --- /dev/null +++ b/c/src/lib/libbsp/mips/shared/irq/i8259.c @@ -0,0 +1,331 @@ +/** + * @file + * + * This file was based upon the powerpc and the i386. + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +/* + * Copyright (C) 1998, 1999 valette@crf.canon.fr + */ + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/i8259.h> +#include <bsp/pci.h> +#include <bsp/irq-generic.h> + + +#define DEBUG_8259 1 + +#define ValidateIrqLine( _irq ) \ + if ( ((int)_irq < 0) ||((int)_irq > 16)) return 1; + +/*-------------------------------------------------------------------------+ +| 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. + */ +volatile rtems_i8259_masks i8259s_cache = 0xfffb; + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_disable_at_i8259s +| Description: Mask IRQ line in appropriate PIC chip. +| Global Variables: i8259s_cache +| Arguments: vector_offset - number of IRQ line to mask. +| Returns: original state or -1 on error. ++--------------------------------------------------------------------------*/ +int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_level level; + int rval; + + ValidateIrqLine(irqLine); + + rtems_interrupt_disable(level); + + /* Recalculate the value */ + mask = 1 << irqLine; + rval = i8259s_cache & mask ? 0 : 1; + i8259s_cache |= mask; + + /* Determine which chip and write the value. */ + if (irqLine < 8) { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + i8259s_cache & 0xff + ); + } else { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + } + + rtems_interrupt_enable(level); + + return rval; +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_enable_at_i8259s +| Description: Unmask IRQ line in appropriate PIC chip. +| Global Variables: i8259s_cache +| Arguments: irqLine - number of IRQ line to mask. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_level level; + + ValidateIrqLine( irqLine ); + + rtems_interrupt_disable(level); + + /* Calculate the value */ + mask = ~(1 << irqLine); + i8259s_cache &= mask; + + /* Determine which chip and write the value */ + if (irqLine < 8) { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + i8259s_cache & 0xff + ); + } else { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + } + + rtems_interrupt_enable(level); + + return 0; +} /* mask_irq */ + + +int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine) +{ + unsigned short mask; + + ValidateIrqLine( irqLine ); + + mask = (1 << irqLine); + + return (~(i8259s_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) +{ + if (irqLine >= 8) { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + SLAVE_PIC_EOSI + ); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_COMMAND_IO_PORT, + (PIC_EOSI | (irqLine - 8)) + ); + }else { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + (PIC_EOSI | irqLine) + ); + } + + return 0; + +} /* ackIRQ */ + +void BSP_i8259s_init(void) +{ + volatile uint32_t i; + + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xff ); + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xff ); + + + /* + * init master 8259 interrupt controller + */ + + /* Start init sequence */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + 0x11 + ); + /* Vector base = 0 */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + 0x00 + ); + + /* edge tiggered, Cascade (slave) on IRQ2 */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + 0x04 + ); + + /* Select 8086 mode */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + 0x01 + ); + + /* + * init slave interrupt controller + */ + + /* Start init sequence */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_COMMAND_IO_PORT, 0x11); + + /* Vector base = 8 */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0x08); + + /* edge triggered, Cascade (slave) on IRQ2 */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0x02); + + /* Select 8086 mode */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0x01); + + /* Mask all except cascade */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xFB); + + /* Mask all */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xFF); + + /* + * Enable all interrupts in debug mode. + */ + + if ( DEBUG_8259 ) { + i8259s_cache = 0x0101; + } + + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + i8259s_cache & 0xff + ); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + + for (i=0; i<10000; i++); +} + +#define PCI__GEN(bus, off, num) (((off)^((bus) << 7))+((num) << 4)) +#define PCI_INTR_ACK(bus) PCI__GEN(bus, 0x0c34, 0) + +volatile uint8_t master; +volatile uint8_t slave; +volatile uint8_t temp; + +void bsp_show_interrupt_regs(void); +void bsp_show_interrupt_regs() { + unsigned int sr; + unsigned int cause; + unsigned int pending; + + mips_get_sr( sr ); + mips_get_cause( cause ); + pending = (cause & sr & 0xff00) >> CAUSE_IPSHIFT; + + master = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_COMMAND_IO_PORT); + slave = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_COMMAND_IO_PORT); + + printk("sr: 0x%x cause: 0x%x pending: 0x%x master: 0x%x slave: 0x%x\n", + sr, cause, pending, master, slave + ); +} + +int BSP_i8259s_int_process() +{ + uint8_t irq; + volatile uint32_t temp; + + /* Get the Interrupt */ + irq = simple_in_le32(BSP_PCI_BASE_ADDRESS, PCI_INTR_ACK(0) ); + + /* + * Mask interrupts + * + Mask all except cascade on master + * + Mask all on slave + */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xFB); + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xFF); + + /* Call the Handler */ + temp = irq + MALTA_SB_IRQ_0; + bsp_interrupt_handler_dispatch( temp ); + + /* Reset the interrupt on the 8259 either the master or the slave chip */ + if (irq & 8) { + temp = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT); + + /* Mask all */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xFF); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_COMMAND_IO_PORT, + (PIC_EOSI + (irq&7)) + ); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + SLAVE_PIC_EOSI + ); + } else { + temp = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT); + /* Mask all except cascade */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xFB); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + (PIC_EOSI+irq) + ); + } + + /* Restore the interrupts */ + simple_out_8(BSP_8259_BASE_ADDRESS,PIC_MASTER_IMR_IO_PORT,i8259s_cache&0xff); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + + return 0; +} |