blob: b35ef7c8c07cb83ea3b1017f892fc7546ef9c094 [file] [log] [blame]
/*
* Copyright (c) 2016, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "qm_common.h"
#include "qm_interrupt.h"
#include "idt.h"
#if (HAS_APIC)
#include "apic.h"
#elif(HAS_MVIC)
#include "mvic.h"
#elif(QM_SENSOR)
#include "qm_ss_interrupt.h"
#include "qm_sensor_regs.h"
extern qm_ss_isr_t __ivt_vect_table[];
#else
#error "Unsupported / unspecified processor detected."
#endif
/* SCSS base addr for LMT interrupt routing, for linear IRQ mapping */
#define SCSS_LMT_INT_MASK_BASE (&QM_SCSS_INT->int_i2c_mst_0_mask)
#if (QM_SENSOR)
#define SCSS_INT_MASK BIT(8) /* Sensor Subsystem interrupt masking */
static void ss_register_irq(unsigned int vector);
#else
#define SCSS_INT_MASK BIT(0) /* Lakemont interrupt masking */
#endif
void qm_irq_disable(void)
{
#if (QM_SENSOR)
qm_ss_irq_disable();
#else
__asm__ __volatile__("cli");
#endif
}
void qm_irq_enable(void)
{
#if (QM_SENSOR)
qm_ss_irq_enable();
#else
__asm__ __volatile__("sti");
#endif
}
void qm_irq_mask(uint32_t irq)
{
#if (HAS_APIC)
ioapic_mask_irq(irq);
#elif(HAS_MVIC)
mvic_mask_irq(irq);
#elif(QM_SENSOR)
qm_ss_irq_mask(irq);
#endif
}
void qm_irq_unmask(uint32_t irq)
{
#if (HAS_APIC)
ioapic_unmask_irq(irq);
#elif(HAS_MVIC)
mvic_unmask_irq(irq);
#elif(QM_SENSOR)
qm_ss_irq_unmask(irq);
#endif
}
void _qm_irq_setup(uint32_t irq, uint16_t register_offset)
{
uint32_t *scss_intmask;
#if (HAS_APIC)
/*
* Quark SE SOC has an APIC. Other SoCs uses a simple, fixed-vector
* non-8259 PIC that requires no configuration.
*/
ioapic_register_irq(irq, QM_IRQ_TO_VECTOR(irq));
#elif(HAS_MVIC)
mvic_register_irq(irq);
#elif(QM_SENSOR)
ss_register_irq(QM_IRQ_TO_VECTOR(irq));
#endif
/* Route peripheral interrupt to Lakemont/Sensor Subsystem */
scss_intmask = (uint32_t *)SCSS_LMT_INT_MASK_BASE + register_offset;
#if (QUARK_SE || QUARK_D2000 || QM_SENSOR)
/* On Quark D2000 and Quark SE the register for the analog comparator
* host mask has a different bit field than the other host mask
* registers. */
if (QM_IRQ_AC_MASK_OFFSET == register_offset) {
*scss_intmask &= ~0x0007ffff;
#if !defined(QUARK_D2000)
} else if (QM_IRQ_MBOX_MASK_OFFSET == register_offset) {
/* Masking MAILBOX irq id done inside mbox driver */
#endif
} else {
*scss_intmask &= ~SCSS_INT_MASK;
}
#else
*scss_intmask &= ~SCSS_INT_MASK;
#endif
#if (HAS_APIC)
ioapic_unmask_irq(irq);
#elif(HAS_MVIC)
mvic_unmask_irq(irq);
#elif(QM_SENSOR)
qm_ss_irq_unmask(QM_IRQ_TO_VECTOR(irq));
#endif
}
/*
* Register an Interrupt Service Routine to a given interrupt vector.
*
* @param[in] vector Interrupt Vector number.
* @param[in] isr ISR to register to given vector. Must be a valid x86 ISR.
* If this can't be provided, qm_irq_request() or
* qm_int_vector_request() should be used instead.
*/
void _qm_register_isr(uint32_t vector, qm_isr_t isr)
{
#if (QM_SENSOR)
/* Invalidate the i-cache line which contains the IRQ vector. This
* will bypass i-cache and set vector with the good ISR. */
__builtin_arc_sr((uint32_t)&__ivt_vect_table[0] + (vector * 4),
QM_SS_AUX_IC_IVIL);
/* All SR accesses to the IC_IVIL register must be followed by three
* NOP instructions, see chapter 3.3.59 in the datasheet
* "ARC_V2_ProgrammersReference.pdf" */
__builtin_arc_nop();
__builtin_arc_nop();
__builtin_arc_nop();
__ivt_vect_table[vector] = isr;
#else
idt_set_intr_gate_desc(vector, (uint32_t)isr);
#endif
}
#if (QM_SENSOR)
static void ss_register_irq(unsigned int vector)
{
/*
* By hardware power-on default, SS interrupts are level triggered.
* The following switch statement sets some of the peripherals to edge
* triggered.
*/
switch (vector) {
case QM_SS_IRQ_ADC_PWR_VECTOR:
case QM_IRQ_RTC_0_VECTOR:
case QM_IRQ_AONPT_0_VECTOR:
case QM_IRQ_WDT_0_VECTOR:
/* Edge sensitive. */
__builtin_arc_sr(vector, QM_SS_AUX_IRQ_SELECT);
__builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE,
QM_SS_AUX_IRQ_TRIGGER);
}
}
#endif