Hi Simon, On Wed, Nov 12, 2014 at 8:18 AM, Simon Glass <s...@chromium.org> wrote: > The i8259 is a basic interrupt controller from the 1970s which is still > present in modern Intel hardware. Add some code to set it up. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > arch/x86/include/asm/i8259.h | 3 + > arch/x86/lib/Makefile | 1 + > arch/x86/lib/i8259.c | 134 > +++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 138 insertions(+) > create mode 100644 arch/x86/lib/i8259.c > > diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h > index 73113f9..bac073d 100644 > --- a/arch/x86/include/asm/i8259.h > +++ b/arch/x86/include/asm/i8259.h > @@ -69,4 +69,7 @@ > #define ICW4_AEOI 0x02 /* Automatic EOI Mode */ > #define ICW4_PM 0x01 /* Microprocessor Mode */ > > +void i8259_setup(void); > +void i8259_configure_irq_trigger(int int_num, bool is_level_triggered); > + > #endif > diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile > index d0c7f30..2d75f9f 100644 > --- a/arch/x86/lib/Makefile > +++ b/arch/x86/lib/Makefile > @@ -8,6 +8,7 @@ > obj-$(CONFIG_CMD_BOOTM) += bootm.o > obj-y += cmd_boot.o > obj-y += gcc.o > +obj-y += i8259.o > obj-y += init_helpers.o > obj-y += interrupts.o > obj-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o > diff --git a/arch/x86/lib/i8259.c b/arch/x86/lib/i8259.c > new file mode 100644 > index 0000000..442d904 > --- /dev/null > +++ b/arch/x86/lib/i8259.c > @@ -0,0 +1,134 @@ > +/* > + * From Coreboot file of the same name > + * > + * Copyright (C) 2009 coresystems GmbH > + * > + * SPDX-License-Identifier: GPL-2.0 > + */ > + > +#include <common.h> > +#include <asm/io.h> > +#include <asm/i8259.h> > + > +#define MASTER_PIC_ICW1 0x20 > +#define SLAVE_PIC_ICW1 0xa0 > +#define ICW_SELECT (1 << 4) > +#define OCW_SELECT (0 << 4) > +#define ADI (1 << 2) > +#define SNGL (1 << 1) > +#define IC4 (1 << 0) > + > +#define MASTER_PIC_ICW2 0x21 > +#define SLAVE_PIC_ICW2 0xa1 > +#define INT_VECTOR_MASTER 0x20 > +#define IRQ0 0x00 > +#define IRQ1 0x01 > +#define INT_VECTOR_SLAVE 0x28 > +#define IRQ8 0x00 > +#define IRQ9 0x01 > + > +#define MASTER_PIC_ICW3 0x21 > +#define CASCADED_PIC (1 << 2) > + > +#define MASTER_PIC_ICW4 0x21 > +#define SLAVE_PIC_ICW4 0xa1 > +#define MICROPROCESSOR_MODE (1 << 0) > + > +#define SLAVE_PIC_ICW3 0xa1 > +#define SLAVE_ID 0x02 > + > +#define MASTER_PIC_OCW1 0x21 > +#define SLAVE_PIC_OCW1 0xa1 > +#define IRQ2 (1 << 2) > +#define ALL_IRQS 0xff > + > +#define ELCR1 0x4d0 > +#define ELCR2 0x4d1 > + > +void i8259_setup(void) > +{ > + /* A write to ICW1 starts the Interrupt Controller Initialization > + * Sequence. This implicitly causes the following to happen: > + * - Interrupt Mask register is cleared > + * - Priority 7 is assigned to IRQ7 input > + * - Slave mode address is set to 7 > + * - Special mask mode is cleared > + * > + * We send the initialization sequence to both the master and > + * slave i8259 controller. > + */ > + outb(ICW_SELECT|IC4, MASTER_PIC_ICW1); > + outb(ICW_SELECT|IC4, SLAVE_PIC_ICW1); > + > + /* Now the interrupt controller expects us to write to ICW2. */ > + outb(INT_VECTOR_MASTER | IRQ0, MASTER_PIC_ICW2); > + outb(INT_VECTOR_SLAVE | IRQ8, SLAVE_PIC_ICW2); > + > + /* Now the interrupt controller expects us to write to ICW3. > + * > + * The normal scenario is to set up cascading on IRQ2 on the master > + * i8259 and assign the slave ID 2 to the slave i8259. > + */ > + outb(CASCADED_PIC, MASTER_PIC_ICW3); > + outb(SLAVE_ID, SLAVE_PIC_ICW3); > + > + /* Now the interrupt controller expects us to write to ICW4. > + * > + * We switch both i8259 to microprocessor mode because they're > + * operating as part of an x86 architecture based chipset > + */ > + outb(MICROPROCESSOR_MODE, MASTER_PIC_ICW2); > + outb(MICROPROCESSOR_MODE, SLAVE_PIC_ICW2); > + > + /* Now clear the interrupts through OCW1. > + * First we mask off all interrupts on the slave interrupt controller > + * then we mask off all interrupts but interrupt 2 on the master > + * controller. This way the cascading stays alife. > + */ > + outb(ALL_IRQS, SLAVE_PIC_OCW1); > + outb(ALL_IRQS & ~IRQ2, MASTER_PIC_OCW1); > + debug("i8259 inited\n"); > +} > + > +/** > + * i8259_configure_irq_trigger() - Configure IRQ triggering > + * > + * Switch the given interrupt to be level / edge triggered > + * > + * @param int_num legacy interrupt number (3-7, 9-15) > + * @param is_level_triggered true for level triggered interrupt, false for > + * edge triggered interrupt > + */ > +void i8259_configure_irq_trigger(int int_num, bool is_level_triggered) > +{ > + u16 int_bits = inb(ELCR1) | (((u16)inb(ELCR2)) << 8); > + > + debug("%s: current interrupts are 0x%x\n", __func__, int_bits); > + if (is_level_triggered) > + int_bits |= (1 << int_num); > + else > + int_bits &= ~(1 << int_num); > + > + /* Write new values */ > + debug("%s: try to set interrupts 0x%x\n", __func__, int_bits); > + outb((u8)(int_bits & 0xff), ELCR1); > + outb((u8)(int_bits >> 8), ELCR2); > + > +#ifdef PARANOID_IRQ_TRIGGERS > + /* > + * Try reading back the new values. This seems like an error but is > + * not > + */ > + if (inb(ELCR1) != (int_bits & 0xff)) { > + printf("%s: lower order bits are wrong: want 0x%x, got > 0x%x\n", > + __func__, (int_bits & 0xff), inb(ELCR1)); > + } > + > + if (inb(ELCR2) != (int_bits >> 8)) { > + printf("%s: higher order bits are wrong: want 0x%x, got > 0x%x\n", > + __func__, (int_bits>>8), inb(ELCR2)); > + } > +#endif > +} > + > + > --
Can you make the changes to the existing arch/x86/lib/pcat_interrupts.c which is also the i8259 pic driver initialization? Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot