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