/* * Copyright (c) 2007-2017 Allwinnertech Co., Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * 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. * */ /* ********************************************************************************************************* * LINUX-KERNEL * AllWinner Linux Platform Develop Kits * Kernel Module * * (c) Copyright 2006-2011, kevin.z China * All Rights Reserved * * File : mem_int.c * By : gq.yang * Version : v1.0 * Date : 2012-11-3 20:13 * Descript: interrupt for platform mem * Update : date auther ver notes ********************************************************************************************************* */ #include "pm_i.h" static void *GicDDisc; static void *GicCDisc; static u32 gic_d_len; static u32 gic_c_len; /* * STANDBY INTERRUPT INITIALISE * * Description: mem interrupt initialise. * * Arguments : none. * * Returns : 0/-1; */ __s32 mem_int_init(void) { u32 *base = 0; pm_get_dev_info("gic", 0, &base, &gic_d_len); GicDDisc = base; pm_get_dev_info("gic", 1, &base, &gic_c_len); GicCDisc = base; return 0; } __s32 mem_int_save(void) { #if defined(CONFIG_ARCH_SUN8IW10P1) || defined(CONFIG_ARCH_SUN8IW11P1) __u32 i = 0; /*printk("gic iar == 0x%x. \n", *(volatile __u32 *)(IO_ADDRESS(SUNXI_GIC_CPU_PBASE)+0x0c)); */ /* initialise interrupt enable and mask for mem */ /* * Disable all interrupts. Leave the PPI and SGIs alone * as these enables are banked registers. */ for (i = 4; i < (GIC_400_ENABLE_LEN); i += 4) *(volatile __u32 *)(GicDDisc + GIC_DIST_ENABLE_CLEAR + i) = 0xffffffff; /*config cpu interface */ #if 0 *(volatile __u32 *)(GicCDisc + GIC_CPU_PRIMASK) = 0xf0; *(volatile __u32 *)(GicCDisc + GIC_CPU_CTRL) = 0x1; #endif #if 1 /* clear external irq pending: needed */ for (i = 4; i < (GIC_400_ENABLE_LEN); i += 4) *(volatile __u32 *)(GicDDisc + GIC_DIST_PENDING_CLEAR + i) = 0xffffffff; #endif /*the print info just to check the pending state, actually, after u read iar, u need to access end of interrupt reg; */ i = *(volatile __u32 *)(GicCDisc + 0x0c); if (i != 0x3ff) { /*u need to */ *(volatile __u32 *)(GicCDisc + 0x10) = i; printk("notice: gic iar == 0x%x. \n", i); } #endif return 0; } /* * mem_int_restore * * Description: mem interrupt exit. * * Arguments : none. * * Returns : 0/-1; */ __s32 mem_int_restore(void) { #if defined(CONFIG_ARCH_SUN8IW10P1) || defined(CONFIG_ARCH_SUN8IW11P1) int i = 0; volatile __u32 enable_bit = 0; /*all the disable-int-src pending, need to be clear */ for (i = 0; i < GIC_400_ENABLE_LEN; i += 4) { enable_bit = *(volatile __u32 *)(GicDDisc + GIC_DIST_ENABLE_SET + i); *(volatile __u32 *)(GicDDisc + GIC_DIST_PENDING_CLEAR + i) &= (~enable_bit); } #endif return 0; } /* ********************************************************************************************************* * QUERY INTERRUPT * * Description: enable interrupt. * * Arguments : src interrupt source number. * * Returns : 0/-1; ********************************************************************************************************* */ __s32 mem_enable_int(enum interrupt_source_e src) { __u32 tmpGrp = (__u32) src >> 5; __u32 tmpSrc = (__u32) src & 0x1f; if (0 == src) { return -1; } /*enable interrupt source */ /*printk("GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4 = 0x%p. tmpGrp = 0x%x.\n", GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4, tmpGrp); */ /*printk("GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4 = 0x%x. tmpGrp = 0x%x.\n", *(volatile __u32 *)(GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4), tmpGrp); */ *(volatile __u32 *)(GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp * 4) |= (1 << tmpSrc); /*printk("GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4 = 0x%p. tmpGrp = 0x%x.\n", GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4, tmpGrp); */ /*printk("GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4 = 0x%x. tmpGrp = 0x%x.\n", *(volatile __u32 *)(GicDDisc + GIC_DIST_ENABLE_SET + tmpGrp*4), tmpGrp); */ /*printk("tmpSrc = 0x%x. \n", tmpSrc); */ /*need to care mask or priority? */ return 0; } /* ********************************************************************************************************* * QUERY INTERRUPT * * Description: query interrupt. * * Arguments : src interrupt source number. * * Returns : 0/-1; ********************************************************************************************************* */ __s32 mem_query_int(enum interrupt_source_e src) { __s32 result = 0; __u32 tmpGrp = (__u32) src >> 5; __u32 tmpSrc = (__u32) src & 0x1f; if (0 == src) { return -1; } result = *(volatile __u32 *)(GicDDisc + GIC_DIST_PENDING_SET + tmpGrp * 4) & (1 << tmpSrc); /*printk("GicDDisc + GIC_DIST_PENDING_SET + tmpGrp*4 = 0x%x. tmpGrp = 0x%x.\n", GicDDisc + GIC_DIST_PENDING_SET + tmpGrp*4, tmpGrp); */ /*printk("tmpSrc = 0x%x. result = 0x%x. \n", tmpSrc, result); */ return result ? 0 : -1; }