You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.4 KiB
233 lines
6.4 KiB
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#include "gsi_emulation.h"
|
|
|
|
/*
|
|
* *****************************************************************************
|
|
* The following used to set up the EMULATION interrupt controller...
|
|
* *****************************************************************************
|
|
*/
|
|
int setup_emulator_cntrlr(
|
|
void __iomem *intcntrlr_base,
|
|
u32 intcntrlr_mem_size)
|
|
{
|
|
uint32_t val, ver, intrCnt, rangeCnt, range;
|
|
|
|
val = gsi_emu_readl(intcntrlr_base + GE_INT_CTL_VER_CNT);
|
|
|
|
intrCnt = val & 0xFFFF;
|
|
ver = (val >> 16) & 0xFFFF;
|
|
rangeCnt = intrCnt / 32;
|
|
|
|
GSIDBG(
|
|
"CTL_VER_CNT reg val(0x%x) intr cnt(%u) cntrlr ver(0x%x) rangeCnt(%u)\n",
|
|
val, intrCnt, ver, rangeCnt);
|
|
|
|
/*
|
|
* Verify the interrupt controller version
|
|
*/
|
|
if (ver == 0 || ver == 0xFFFF || ver < DEO_IC_INT_CTL_VER_MIN) {
|
|
GSIERR(
|
|
"Error: invalid interrupt controller version 0x%x\n",
|
|
ver);
|
|
return -GSI_STATUS_INVALID_PARAMS;
|
|
}
|
|
|
|
/*
|
|
* Verify the interrupt count
|
|
*
|
|
* NOTE: intrCnt must be at least one block and multiple of 32
|
|
*/
|
|
if ((intrCnt % 32) != 0) {
|
|
GSIERR(
|
|
"Invalid interrupt count read from HW 0x%04x\n",
|
|
intrCnt);
|
|
return -GSI_STATUS_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Calculate number of ranges used, each range handles 32 int lines
|
|
*/
|
|
if (rangeCnt > DEO_IC_MAX_RANGE_CNT) {
|
|
GSIERR(
|
|
"SW interrupt limit(%u) passed, increase DEO_IC_MAX_RANGE_CNT(%u)\n",
|
|
rangeCnt,
|
|
DEO_IC_MAX_RANGE_CNT);
|
|
return -GSI_STATUS_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Let's take the last register offset minus the first
|
|
* register offset (ie. range) and compare it to the interrupt
|
|
* controller's dtsi defined memory size. The range better
|
|
* fit within the size.
|
|
*/
|
|
val = GE_SOFT_INT_n(rangeCnt-1) - GE_INT_CTL_VER_CNT;
|
|
if (val > intcntrlr_mem_size) {
|
|
GSIERR(
|
|
"Interrupt controller register range (%u) exceeds dtsi provisioned size (%u)\n",
|
|
val, intcntrlr_mem_size);
|
|
return -GSI_STATUS_ERROR;
|
|
}
|
|
|
|
/*
|
|
* The following will disable the emulators interrupt controller,
|
|
* so that we can config it...
|
|
*/
|
|
GSIDBG("Writing GE_INT_MASTER_ENABLE\n");
|
|
gsi_emu_writel(
|
|
0x0,
|
|
intcntrlr_base + GE_INT_MASTER_ENABLE);
|
|
|
|
/*
|
|
* Init register maps of all ranges
|
|
*/
|
|
for (range = 0; range < rangeCnt; range++) {
|
|
/*
|
|
* Disable all int sources by setting all enable clear bits
|
|
*/
|
|
GSIDBG("Writing GE_INT_ENABLE_CLEAR_n(%u)\n", range);
|
|
gsi_emu_writel(
|
|
0xFFFFFFFF,
|
|
intcntrlr_base + GE_INT_ENABLE_CLEAR_n(range));
|
|
|
|
/*
|
|
* Clear all raw statuses
|
|
*/
|
|
GSIDBG("Writing GE_INT_CLEAR_n(%u)\n", range);
|
|
gsi_emu_writel(
|
|
0xFFFFFFFF,
|
|
intcntrlr_base + GE_INT_CLEAR_n(range));
|
|
|
|
/*
|
|
* Init all int types
|
|
*/
|
|
GSIDBG("Writing GE_INT_TYPE_n(%u)\n", range);
|
|
gsi_emu_writel(
|
|
0x0,
|
|
intcntrlr_base + GE_INT_TYPE_n(range));
|
|
}
|
|
|
|
/*
|
|
* The following tells the interrupt controller to interrupt us
|
|
* when it sees interupts from ipa and/or gsi.
|
|
*
|
|
* Interrupts:
|
|
* ===================================================================
|
|
* DUT0 [ 63 : 16 ]
|
|
* ipa_irq [ 3 : 0 ] <---HERE
|
|
* ipa_gsi_bam_irq [ 7 : 4 ] <---HERE
|
|
* ipa_bam_apu_sec_error_irq [ 8 ]
|
|
* ipa_bam_apu_non_sec_error_irq [ 9 ]
|
|
* ipa_bam_xpu2_msa_intr [ 10 ]
|
|
* ipa_vmidmt_nsgcfgirpt [ 11 ]
|
|
* ipa_vmidmt_nsgirpt [ 12 ]
|
|
* ipa_vmidmt_gcfgirpt [ 13 ]
|
|
* ipa_vmidmt_girpt [ 14 ]
|
|
* bam_xpu3_qad_non_secure_intr_sp [ 15 ]
|
|
*/
|
|
GSIDBG("Writing GE_INT_ENABLE_n(0)\n");
|
|
gsi_emu_writel(
|
|
0x00FF, /* See <---HERE above */
|
|
intcntrlr_base + GE_INT_ENABLE_n(0));
|
|
|
|
/*
|
|
* The following will enable the IC post config...
|
|
*/
|
|
GSIDBG("Writing GE_INT_MASTER_ENABLE\n");
|
|
gsi_emu_writel(
|
|
0x1,
|
|
intcntrlr_base + GE_INT_MASTER_ENABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* *****************************************************************************
|
|
* The following for EMULATION hard irq...
|
|
* *****************************************************************************
|
|
*/
|
|
irqreturn_t emulator_hard_irq_isr(
|
|
int irq,
|
|
void *ctxt)
|
|
{
|
|
struct gsi_ctx *gsi_ctx_ptr = (struct gsi_ctx *) ctxt;
|
|
|
|
uint32_t val;
|
|
|
|
val = gsi_emu_readl(gsi_ctx_ptr->intcntrlr_base + GE_INT_MASTER_STATUS);
|
|
|
|
/*
|
|
* If bit zero is set, interrupt is for us, hence return IRQ_NONE
|
|
* when it's not set...
|
|
*/
|
|
if (!(val & 0x00000001))
|
|
return IRQ_NONE;
|
|
|
|
/*
|
|
* The following will mask (ie. turn off) future interrupts from
|
|
* the emulator's interrupt controller. It wil stay this way until
|
|
* we turn back on...which will be done in the bottom half
|
|
* (ie. emulator_soft_irq_isr)...
|
|
*/
|
|
gsi_emu_writel(
|
|
0x0,
|
|
gsi_ctx_ptr->intcntrlr_base + GE_INT_OUT_ENABLE);
|
|
|
|
return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
/*
|
|
* *****************************************************************************
|
|
* The following for EMULATION soft irq...
|
|
* *****************************************************************************
|
|
*/
|
|
irqreturn_t emulator_soft_irq_isr(
|
|
int irq,
|
|
void *ctxt)
|
|
{
|
|
struct gsi_ctx *gsi_ctx_ptr = (struct gsi_ctx *) ctxt;
|
|
|
|
irqreturn_t retVal = IRQ_HANDLED;
|
|
uint32_t val;
|
|
|
|
val = gsi_emu_readl(gsi_ctx_ptr->intcntrlr_base + GE_IRQ_STATUS_n(0));
|
|
|
|
GSIDBG("Got irq(%d) with status(0x%08X)\n", irq, val);
|
|
|
|
if (val & 0xF0 && gsi_ctx_ptr->intcntrlr_gsi_isr) {
|
|
GSIDBG("Got gsi interrupt\n");
|
|
retVal = gsi_ctx_ptr->intcntrlr_gsi_isr(irq, ctxt);
|
|
}
|
|
|
|
if (val & 0x0F && gsi_ctx_ptr->intcntrlr_client_isr) {
|
|
GSIDBG("Got ipa interrupt\n");
|
|
retVal = gsi_ctx_ptr->intcntrlr_client_isr(irq, 0);
|
|
}
|
|
|
|
/*
|
|
* The following will clear the interrupts...
|
|
*/
|
|
gsi_emu_writel(
|
|
0xFFFFFFFF,
|
|
gsi_ctx_ptr->intcntrlr_base + GE_INT_CLEAR_n(0));
|
|
|
|
/*
|
|
* The following will unmask (ie. turn on) future interrupts from
|
|
* the emulator's interrupt controller...
|
|
*/
|
|
gsi_emu_writel(
|
|
0x1,
|
|
gsi_ctx_ptr->intcntrlr_base + GE_INT_OUT_ENABLE);
|
|
|
|
return retVal;
|
|
}
|
|
|