10d163575Sopenharmony_ci/*
20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
30d163575Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
40d163575Sopenharmony_ci *
50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
60d163575Sopenharmony_ci * are permitted provided that the following conditions are met:
70d163575Sopenharmony_ci *
80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of
90d163575Sopenharmony_ci *    conditions and the following disclaimer.
100d163575Sopenharmony_ci *
110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list
120d163575Sopenharmony_ci *    of conditions and the following disclaimer in the documentation and/or other materials
130d163575Sopenharmony_ci *    provided with the distribution.
140d163575Sopenharmony_ci *
150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used
160d163575Sopenharmony_ci *    to endorse or promote products derived from this software without specific prior written
170d163575Sopenharmony_ci *    permission.
180d163575Sopenharmony_ci *
190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300d163575Sopenharmony_ci */
310d163575Sopenharmony_ci
320d163575Sopenharmony_ci#include "gic_common.h"
330d163575Sopenharmony_ci#include "los_hwi.h"
340d163575Sopenharmony_ci#include "los_hwi_pri.h"
350d163575Sopenharmony_ci#include "los_mp.h"
360d163575Sopenharmony_ci
370d163575Sopenharmony_ciSTATIC_ASSERT(OS_USER_HWI_MAX <= 1020, "hwi max is too large!");
380d163575Sopenharmony_ci
390d163575Sopenharmony_ci#ifdef LOSCFG_ARCH_GIC_V2
400d163575Sopenharmony_ci
410d163575Sopenharmony_ciSTATIC UINT32 g_curIrqNum = 0;
420d163575Sopenharmony_ci
430d163575Sopenharmony_ci#ifdef LOSCFG_KERNEL_SMP
440d163575Sopenharmony_ci/*
450d163575Sopenharmony_ci * filter description
460d163575Sopenharmony_ci *   0b00: forward to the cpu interfaces specified in cpu_mask
470d163575Sopenharmony_ci *   0b01: forward to all cpu interfaces
480d163575Sopenharmony_ci *   0b10: forward only to the cpu interface that request the irq
490d163575Sopenharmony_ci */
500d163575Sopenharmony_ciSTATIC VOID GicWriteSgi(UINT32 vector, UINT32 cpuMask, UINT32 filter)
510d163575Sopenharmony_ci{
520d163575Sopenharmony_ci    UINT32 val = ((filter & 0x3) << 24) | ((cpuMask & 0xFF) << 16) | /* 24, 16: Register bit offset */
530d163575Sopenharmony_ci                 (vector & 0xF);
540d163575Sopenharmony_ci
550d163575Sopenharmony_ci    GIC_REG_32(GICD_SGIR) = val;
560d163575Sopenharmony_ci}
570d163575Sopenharmony_ci
580d163575Sopenharmony_ciVOID HalIrqSendIpi(UINT32 target, UINT32 ipi)
590d163575Sopenharmony_ci{
600d163575Sopenharmony_ci    GicWriteSgi(ipi, target, 0);
610d163575Sopenharmony_ci}
620d163575Sopenharmony_ci
630d163575Sopenharmony_ciVOID HalIrqSetAffinity(UINT32 vector, UINT32 cpuMask)
640d163575Sopenharmony_ci{
650d163575Sopenharmony_ci    UINT32 offset = vector / 4; /* 4: Interrupt bit width */
660d163575Sopenharmony_ci    UINT32 index = vector & 0x3;
670d163575Sopenharmony_ci
680d163575Sopenharmony_ci    GIC_REG_8(GICD_ITARGETSR(offset) + index) = cpuMask;
690d163575Sopenharmony_ci}
700d163575Sopenharmony_ci#endif
710d163575Sopenharmony_ci
720d163575Sopenharmony_ciUINT32 HalCurIrqGet(VOID)
730d163575Sopenharmony_ci{
740d163575Sopenharmony_ci    return g_curIrqNum;
750d163575Sopenharmony_ci}
760d163575Sopenharmony_ci
770d163575Sopenharmony_ciVOID HalIrqMask(UINT32 vector)
780d163575Sopenharmony_ci{
790d163575Sopenharmony_ci    if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
800d163575Sopenharmony_ci        return;
810d163575Sopenharmony_ci    }
820d163575Sopenharmony_ci
830d163575Sopenharmony_ci    GIC_REG_32(GICD_ICENABLER(vector / 32)) = 1U << (vector % 32); /* 32: Interrupt bit width */
840d163575Sopenharmony_ci}
850d163575Sopenharmony_ci
860d163575Sopenharmony_ciVOID HalIrqUnmask(UINT32 vector)
870d163575Sopenharmony_ci{
880d163575Sopenharmony_ci    if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
890d163575Sopenharmony_ci        return;
900d163575Sopenharmony_ci    }
910d163575Sopenharmony_ci
920d163575Sopenharmony_ci    GIC_REG_32(GICD_ISENABLER(vector >> 5)) = 1U << (vector % 32); /* 5, 32: Register bit offset */
930d163575Sopenharmony_ci}
940d163575Sopenharmony_ci
950d163575Sopenharmony_ciVOID HalIrqPending(UINT32 vector)
960d163575Sopenharmony_ci{
970d163575Sopenharmony_ci    if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
980d163575Sopenharmony_ci        return;
990d163575Sopenharmony_ci    }
1000d163575Sopenharmony_ci
1010d163575Sopenharmony_ci    GIC_REG_32(GICD_ISPENDR(vector >> 5)) = 1U << (vector % 32); /* 5, 32: Register bit offset */
1020d163575Sopenharmony_ci}
1030d163575Sopenharmony_ci
1040d163575Sopenharmony_ciVOID HalIrqClear(UINT32 vector)
1050d163575Sopenharmony_ci{
1060d163575Sopenharmony_ci    GIC_REG_32(GICC_EOIR) = vector;
1070d163575Sopenharmony_ci}
1080d163575Sopenharmony_ci
1090d163575Sopenharmony_ciVOID HalIrqInitPercpu(VOID)
1100d163575Sopenharmony_ci{
1110d163575Sopenharmony_ci    /* unmask interrupts */
1120d163575Sopenharmony_ci    GIC_REG_32(GICC_PMR) = 0xFF;
1130d163575Sopenharmony_ci
1140d163575Sopenharmony_ci    /* enable gic cpu interface */
1150d163575Sopenharmony_ci    GIC_REG_32(GICC_CTLR) = 1;
1160d163575Sopenharmony_ci}
1170d163575Sopenharmony_ci
1180d163575Sopenharmony_ciVOID HalIrqInit(VOID)
1190d163575Sopenharmony_ci{
1200d163575Sopenharmony_ci    UINT32 i;
1210d163575Sopenharmony_ci
1220d163575Sopenharmony_ci    /* set external interrupts to be level triggered, active low. */
1230d163575Sopenharmony_ci    for (i = 32; i < OS_HWI_MAX_NUM; i += 16) { /* 32: Start interrupt number, 16: Interrupt bit width */
1240d163575Sopenharmony_ci        GIC_REG_32(GICD_ICFGR(i / 16)) = 0; /* 16: Register bit offset */
1250d163575Sopenharmony_ci    }
1260d163575Sopenharmony_ci
1270d163575Sopenharmony_ci    /* set external interrupts to CPU 0 */
1280d163575Sopenharmony_ci    for (i = 32; i < OS_HWI_MAX_NUM; i += 4) { /* 32: Start interrupt number, 4: Interrupt bit width */
1290d163575Sopenharmony_ci        GIC_REG_32(GICD_ITARGETSR(i / 4)) = 0x01010101;
1300d163575Sopenharmony_ci    }
1310d163575Sopenharmony_ci
1320d163575Sopenharmony_ci    /* set priority on all interrupts */
1330d163575Sopenharmony_ci    for (i = 0; i < OS_HWI_MAX_NUM; i += 4) { /* 4: Interrupt bit width */
1340d163575Sopenharmony_ci        GIC_REG_32(GICD_IPRIORITYR(i / 4)) = GICD_INT_DEF_PRI_X4;
1350d163575Sopenharmony_ci    }
1360d163575Sopenharmony_ci
1370d163575Sopenharmony_ci    /* disable all interrupts. */
1380d163575Sopenharmony_ci    for (i = 0; i < OS_HWI_MAX_NUM; i += 32) { /* 32: Interrupt bit width */
1390d163575Sopenharmony_ci        GIC_REG_32(GICD_ICENABLER(i / 32)) = ~0; /* 32: Interrupt bit width */
1400d163575Sopenharmony_ci    }
1410d163575Sopenharmony_ci
1420d163575Sopenharmony_ci    HalIrqInitPercpu();
1430d163575Sopenharmony_ci
1440d163575Sopenharmony_ci    /* enable gic distributor control */
1450d163575Sopenharmony_ci    GIC_REG_32(GICD_CTLR) = 1;
1460d163575Sopenharmony_ci
1470d163575Sopenharmony_ci#ifdef LOSCFG_KERNEL_SMP
1480d163575Sopenharmony_ci    /* register inter-processor interrupt */
1490d163575Sopenharmony_ci    (VOID)LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);
1500d163575Sopenharmony_ci    (VOID)LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);
1510d163575Sopenharmony_ci    (VOID)LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpHaltHandler, 0);
1520d163575Sopenharmony_ci#ifdef LOSCFG_KERNEL_SMP_CALL
1530d163575Sopenharmony_ci    (VOID)LOS_HwiCreate(LOS_MP_IPI_FUNC_CALL, 0xa0, 0, OsMpFuncCallHandler, 0);
1540d163575Sopenharmony_ci#endif
1550d163575Sopenharmony_ci#endif
1560d163575Sopenharmony_ci}
1570d163575Sopenharmony_ci
1580d163575Sopenharmony_ciVOID HalIrqHandler(VOID)
1590d163575Sopenharmony_ci{
1600d163575Sopenharmony_ci    UINT32 iar = GIC_REG_32(GICC_IAR);
1610d163575Sopenharmony_ci    UINT32 vector = iar & 0x3FFU;
1620d163575Sopenharmony_ci
1630d163575Sopenharmony_ci    /*
1640d163575Sopenharmony_ci     * invalid irq number, mainly the spurious interrupts 0x3ff,
1650d163575Sopenharmony_ci     * gicv2 valid irq ranges from 0~1019, we use OS_HWI_MAX_NUM
1660d163575Sopenharmony_ci     * to do the checking.
1670d163575Sopenharmony_ci     */
1680d163575Sopenharmony_ci    if (vector >= OS_HWI_MAX_NUM) {
1690d163575Sopenharmony_ci        return;
1700d163575Sopenharmony_ci    }
1710d163575Sopenharmony_ci    g_curIrqNum = vector;
1720d163575Sopenharmony_ci
1730d163575Sopenharmony_ci    OsInterrupt(vector);
1740d163575Sopenharmony_ci
1750d163575Sopenharmony_ci    /* use original iar to do the EOI */
1760d163575Sopenharmony_ci    GIC_REG_32(GICC_EOIR) = iar;
1770d163575Sopenharmony_ci}
1780d163575Sopenharmony_ci
1790d163575Sopenharmony_ciCHAR *HalIrqVersion(VOID)
1800d163575Sopenharmony_ci{
1810d163575Sopenharmony_ci    UINT32 pidr = GIC_REG_32(GICD_PIDR2V2);
1820d163575Sopenharmony_ci    CHAR *irqVerString = NULL;
1830d163575Sopenharmony_ci
1840d163575Sopenharmony_ci    switch (pidr >> GIC_REV_OFFSET) {
1850d163575Sopenharmony_ci        case GICV1:
1860d163575Sopenharmony_ci            irqVerString = "GICv1";
1870d163575Sopenharmony_ci            break;
1880d163575Sopenharmony_ci        case GICV2:
1890d163575Sopenharmony_ci            irqVerString = "GICv2";
1900d163575Sopenharmony_ci            break;
1910d163575Sopenharmony_ci        default:
1920d163575Sopenharmony_ci            irqVerString = "unknown";
1930d163575Sopenharmony_ci    }
1940d163575Sopenharmony_ci    return irqVerString;
1950d163575Sopenharmony_ci}
1960d163575Sopenharmony_ci
1970d163575Sopenharmony_ci#endif
198