mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 17:11:42 +00:00
added uart port debug selection. in board.h, add "#define CONFIG_ISH_UART_0" for UART Port 0. For port1, use "#define CONFIG_ISH_UART_1" BUG=None BRANCH=None Test='make -j buildall' Change-Id: I5426b1d228ac715574e2ff4f28526232d375221f Reviewed-on: https://chromium-review.googlesource.com/566593 Commit-Ready: Kyoung Il Kim <kyoung.il.kim@intel.com> Tested-by: Kyoung Il Kim <kyoung.il.kim@intel.com> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
152 lines
4.2 KiB
C
152 lines
4.2 KiB
C
/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*
|
|
* Set up the LM2 mIA core & interrupts
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "util.h"
|
|
#include "interrupts.h"
|
|
#include "registers.h"
|
|
#include "task_defs.h"
|
|
#include "irq_handler.h"
|
|
#include "console.h"
|
|
|
|
/* Console output macros */
|
|
#define CPUTS(outstr) cputs(CC_SYSTEM, outstr)
|
|
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
|
|
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
|
|
|
|
/* The IDT - initialized in init.S */
|
|
extern IDT_entry __idt[NUM_VECTORS];
|
|
|
|
/* To count the interrupt nesting depth. Usually it is not nested */
|
|
volatile uint32_t __in_isr;
|
|
|
|
void write_ioapic_reg(const uint32_t reg, const uint32_t val)
|
|
{
|
|
REG32(IOAPIC_IDX) = (uint8_t)reg;
|
|
REG32(IOAPIC_WDW) = val;
|
|
}
|
|
|
|
uint32_t read_ioapic_reg(const uint32_t reg)
|
|
{
|
|
REG32(IOAPIC_IDX) = (uint8_t)reg;
|
|
return REG32(IOAPIC_WDW);
|
|
}
|
|
|
|
void set_ioapic_redtbl_raw(const unsigned irq, const uint32_t val)
|
|
{
|
|
const uint32_t redtbl_lo = IOAPIC_IOREDTBL + 2 * irq;
|
|
const uint32_t redtbl_hi = redtbl_lo + 1;
|
|
|
|
write_ioapic_reg(redtbl_lo, val);
|
|
write_ioapic_reg(redtbl_hi, DEST_APIC_ID);
|
|
}
|
|
|
|
void unmask_interrupt(uint32_t irq)
|
|
{
|
|
uint32_t val;
|
|
const uint32_t redtbl_lo = IOAPIC_IOREDTBL + 2 * irq;
|
|
|
|
val = read_ioapic_reg(redtbl_lo);
|
|
val &= ~IOAPIC_REDTBL_MASK;
|
|
set_ioapic_redtbl_raw(irq, val);
|
|
}
|
|
|
|
void mask_interrupt(uint32_t irq)
|
|
{
|
|
uint32_t val;
|
|
const uint32_t redtbl_lo = IOAPIC_IOREDTBL + 2 * irq;
|
|
|
|
val = read_ioapic_reg(redtbl_lo);
|
|
val |= IOAPIC_REDTBL_MASK;
|
|
set_ioapic_redtbl_raw(irq, val);
|
|
}
|
|
|
|
/* Maps IRQs to vectors. To be programmed in IOAPIC redirection table */
|
|
static const irq_desc_t system_irqs[] = {
|
|
LEVEL_INTR(ISH_I2C0_IRQ, ISH_I2C0_VEC),
|
|
LEVEL_INTR(ISH_I2C1_IRQ, ISH_I2C1_VEC),
|
|
LEVEL_INTR(ISH_I2C2_IRQ, ISH_I2C2_VEC),
|
|
LEVEL_INTR(ISH_IPC_HOST2ISH_IRQ, ISH_IPC_VEC),
|
|
LEVEL_INTR(ISH_HPET_TIMER0_IRQ, ISH_HPET_TIMER0_VEC),
|
|
LEVEL_INTR(ISH_HPET_TIMER1_IRQ, ISH_HPET_TIMER1_VEC),
|
|
LEVEL_INTR(ISH_DEBUG_UART_IRQ, ISH_DEBUG_UART_VEC),
|
|
};
|
|
|
|
|
|
void set_interrupt_gate(uint8_t num, isr_handler_t func, uint8_t flags)
|
|
{
|
|
uint16_t code_segment;
|
|
uint32_t base = (uint32_t) func;
|
|
|
|
__idt[num].ISR_low = (uint16_t) (base & USHRT_MAX);
|
|
__idt[num].ISR_high = (uint16_t) ((base >> 16UL) & USHRT_MAX);
|
|
|
|
/* When the flat model is used the CS will never change. */
|
|
__asm volatile ("mov %%cs, %0":"=r" (code_segment));
|
|
__idt[num].segment_selector = code_segment;
|
|
__idt[num].zero = 0;
|
|
__idt[num].flags = flags;
|
|
}
|
|
|
|
void unhandled_vector(void)
|
|
{
|
|
uint32_t vec = 0xff, i;
|
|
uint32_t ioapic_icr_last = LAPIC_ISR_REG; /* In service register */
|
|
|
|
/* Scan ISRs */
|
|
for (i = 7; i >= 0; i--, ioapic_icr_last -= 0x10) {
|
|
|
|
asm("movl (%1), %0\n" : "=&r" (vec) : "r" (ioapic_icr_last));
|
|
if (vec) {
|
|
vec = (32 * __fls(vec)) + i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CPRINTF("Ignoring vector 0x%0x!\n", vec);
|
|
asm("" : : "a" (vec));
|
|
}
|
|
|
|
/* This needs to be moved to link_defs.h */
|
|
extern const struct irq_data __irq_data[], __irq_data_end[];
|
|
|
|
void init_interrupts(void)
|
|
{
|
|
unsigned entry;
|
|
const struct irq_data *p = __irq_data;
|
|
unsigned num_system_irqs = ARRAY_SIZE(system_irqs);
|
|
unsigned max_entries = (read_ioapic_reg(IOAPIC_VERSION) >> 16) & 0xff;
|
|
|
|
/* Setup gates for IRQs declared by drivers using DECLARE_IRQ */
|
|
for (; p < __irq_data_end; p++)
|
|
set_interrupt_gate(IRQ_TO_VEC(p->irq), p->routine, IDT_FLAGS);
|
|
|
|
/* Mask all interrupts by default in IOAPIC */
|
|
for (entry = 0; entry < max_entries; entry++)
|
|
set_ioapic_redtbl_raw(entry, IOAPIC_REDTBL_MASK);
|
|
|
|
/* Enable pre-defined interrupts */
|
|
for (entry = 0; entry < num_system_irqs; entry++)
|
|
set_ioapic_redtbl_raw(system_irqs[entry].irq,
|
|
system_irqs[entry].vector |
|
|
IOAPIC_REDTBL_DELMOD_FIXED |
|
|
IOAPIC_REDTBL_DESTMOD_PHYS |
|
|
IOAPIC_REDTBL_MASK |
|
|
system_irqs[entry].polarity |
|
|
system_irqs[entry].trigger);
|
|
|
|
set_interrupt_gate(ISH_TS_VECTOR, __switchto, IDT_FLAGS);
|
|
|
|
/* Note: At reset, ID field is already set to 0 in APIC ID register */
|
|
|
|
/* Enable the APIC, mapping the spurious interrupt at the same time. */
|
|
APIC_SPURIOUS_INT = LAPIC_SPURIOUS_INT_VECTOR | APIC_ENABLE_BIT;
|
|
|
|
/* Set timer error vector. */
|
|
APIC_LVT_ERROR = LAPIC_LVT_ERROR_VECTOR;
|
|
}
|