/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License 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 https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * 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.
 *  * Neither the name of the copyright holder 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 COPYRIGHT
 * HOLDER 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.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 *
 * $Author$
 * $Date$
 * $RCSfile: bim_if.c,v $
 * $Revision$
 *
 *---------------------------------------------------------------------------*/

/** @file bim_if.c
 *  bim_if.c The BIM (Bus Interface Module) interface
 */


//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include "x_typedef.h"
#include "x_bim.h"
#include "x_os.h"
#include "x_ckgen.h"

//#define  CC_FIQ_SUPPORT

#ifndef CC_MTK_PRELOADER

#include "x_hal_arm.h"
#include "x_timer.h"

#ifdef CC_ARM_GIC_V3
#define ARM_IRQ_SEC_PHY_TIMER		30

#define ARM_IRQ_SEC_SGI_0		8
#define ARM_IRQ_SEC_SGI_1		9
#define ARM_IRQ_SEC_SGI_2		10
#define ARM_IRQ_SEC_SGI_3		11
#define ARM_IRQ_SEC_SGI_4		12
#define ARM_IRQ_SEC_SGI_5		13
#define ARM_IRQ_SEC_SGI_6		14
#define ARM_IRQ_SEC_SGI_7		15

/*
 * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
 * terminology. On a GICv2 system or mode, the lists will be merged and treated
 * as Group 0 interrupts.
 */
#define ARM_G1S_IRQS			ARM_IRQ_SEC_PHY_TIMER,		\
					ARM_IRQ_SEC_SGI_1,		\
					ARM_IRQ_SEC_SGI_2,		\
					ARM_IRQ_SEC_SGI_3,		\
					ARM_IRQ_SEC_SGI_4,		\
					ARM_IRQ_SEC_SGI_5,		\
					ARM_IRQ_SEC_SGI_7

#define PLAT_ARM_G1S_IRQS		ARM_G1S_IRQS
/* Compute the number of elements in the given array */
#define ARRAY_SIZE(a)				\
	(sizeof(a) / sizeof((a)[0]))

/* Array of Group1 secure interrupts to be configured by the gic driver */
static const unsigned int g1s_interrupt_array[] = {
	PLAT_ARM_G1S_IRQS,107,108,109
};
#endif

//-----------------------------------------------------------------------------
// Static functions
//-----------------------------------------------------------------------------
#ifdef CC_ARM_GIC
#ifdef CC_ARM_GIC_V3
static uint32_t read_mpidr(void)
{
	int mpidr;
	__asm__ volatile("mrc		p15, 0, %0, c0, c0, 5"
		: "=r" (mpidr)
		);
	return mpidr;
}

static unsigned int read_icc_sre_el1(void)
{
	unsigned int icc_sre;
	__asm__ volatile("mrc		p15, 0, %0, c12, c12, 5"
		: "=r" (icc_sre)
		);
	return icc_sre;
}

static void write_icc_sre_el1(unsigned int icc_sre)
{
	__asm__ volatile("mcr		p15, 0, %0, c12, c12, 5"
		: : "r" (icc_sre)
		);
}

static void write_icc_pmr_el1(unsigned int icc_pmr)
{
	__asm__ volatile("mcr		p15, 0, %0, c4, c6, 0"
		: : "r" (icc_pmr)
		);
}

static void write_icc_igrpen0_el1(unsigned int icc_igrpen0)
{
	__asm__ volatile("mcr		p15, 0, %0, c12, c12, 6"
		: : "r" (icc_igrpen0)
		);
}

static void write_icc_igrpen1_el1(unsigned int icc_igrpen1)
{
	__asm__ volatile("mcr		p15, 0, %0, c12, c12, 7"
		: : "r" (icc_igrpen1)
		);
}

#define isb()		asm volatile("isb" : : : "memory")

static inline void write_eoi_el1(UINT32 u4IrqNo)
{
	__asm__ volatile("mcr		p15, 0, %0, c12, c12, 1"
		: : "r" (u4IrqNo)
		);

	isb();
}

/*******************************************************************************
 * GIC Distributor interface accessors for reading entire registers
 ******************************************************************************/
/*
 * Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt
 * `id`, 32 interrupt ids at a time.
 */
unsigned int gicd_read_igroupr(unsigned int id)
{
	unsigned n = id >> IGROUPR_SHIFT;
	return GICR_READ32(GICD_IGROUPR + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ISENABLER corresponding to the
 * interrupt `id`, 32 interrupt ids at a time.
 */
unsigned int gicd_read_isenabler(unsigned int id)
{
	unsigned n = id >> ISENABLER_SHIFT;
	return GICR_READ32(GICD_ISENABLER + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ICENABLER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
unsigned int gicd_read_icenabler(unsigned int id)
{
	unsigned n = id >> ICENABLER_SHIFT;
	return GICR_READ32(GICD_ICENABLER + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ISPENDR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
unsigned int gicd_read_ispendr(unsigned int id)
{
	unsigned n = id >> ISPENDR_SHIFT;
	return GICR_READ32(GICD_ISPENDR + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ICPENDR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
unsigned int gicd_read_icpendr(unsigned int id)
{
	unsigned n = id >> ICPENDR_SHIFT;
	return GICR_READ32(GICD_ICPENDR + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ISACTIVER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
unsigned int gicd_read_isactiver(unsigned int id)
{
	unsigned n = id >> ISACTIVER_SHIFT;
	return GICR_READ32(GICD_ISACTIVER + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ICACTIVER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
unsigned int gicd_read_icactiver(unsigned int id)
{
	unsigned n = id >> ICACTIVER_SHIFT;
	return GICR_READ32(GICD_ICACTIVER + (n << 2));
}

/*
 * Accessor to read the GIC Distributor IPRIORITYR corresponding to the
 * interrupt `id`, 4 interrupt IDs at a time.
 */
unsigned int gicd_read_ipriorityr(unsigned int id)
{
	unsigned n = id >> IPRIORITYR_SHIFT;
	return GICR_READ32(GICD_IPRIORITYR + (n << 2));
}

/*
 * Accessor to read the GIC Distributor ICGFR corresponding to the
 * interrupt `id`, 16 interrupt IDs at a time.
 */
unsigned int gicd_read_icfgr(unsigned int id)
{
	unsigned n = id >> ICFGR_SHIFT;
	return GICR_READ32(GICD_ICFGR + (n << 2));
}

/*
 * Accessor to read the GIC Distributor NSACR corresponding to the
 * interrupt `id`, 16 interrupt IDs at a time.
 */
unsigned int gicd_read_nsacr(unsigned int id)
{
	unsigned n = id >> NSACR_SHIFT;
	return GICR_READ32(GICD_NSACR + (n << 2));
}

/*******************************************************************************
 * GIC Distributor interface accessors for writing entire registers
 ******************************************************************************/
/*
 * Accessor to write the GIC Distributor IGROUPR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_igroupr(unsigned int id, unsigned int val)
{
	unsigned n = id >> IGROUPR_SHIFT;
	GICD_WRITE32(GICD_IGROUPR + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ISENABLER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_isenabler(unsigned int id, unsigned int val)
{
	unsigned n = id >> ISENABLER_SHIFT;
	GICD_WRITE32(GICD_ISENABLER + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ICENABLER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_icenabler(unsigned int id, unsigned int val)
{
	unsigned n = id >> ICENABLER_SHIFT;
	GICD_WRITE32(GICD_ICENABLER + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ISPENDR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_ispendr(unsigned int id, unsigned int val)
{
	unsigned n = id >> ISPENDR_SHIFT;
	GICD_WRITE32(GICD_ISPENDR + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ICPENDR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_icpendr(unsigned int id, unsigned int val)
{
	unsigned n = id >> ICPENDR_SHIFT;
	GICD_WRITE32(GICD_ICPENDR + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ISACTIVER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_isactiver(unsigned int id, unsigned int val)
{
	unsigned n = id >> ISACTIVER_SHIFT;
	GICD_WRITE32(GICD_ISACTIVER + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ICACTIVER corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_icactiver(unsigned int id, unsigned int val)
{
	unsigned n = id >> ICACTIVER_SHIFT;
	GICD_WRITE32(GICD_ICACTIVER + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor IPRIORITYR corresponding to the
 * interrupt `id`, 4 interrupt IDs at a time.
 */
void gicd_write_ipriorityr(unsigned int id, unsigned int val)
{
	unsigned n = id >> IPRIORITYR_SHIFT;
	GICD_WRITE32(GICD_IPRIORITYR + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor ICFGR corresponding to the
 * interrupt `id`, 16 interrupt IDs at a time.
 */
void gicd_write_icfgr(unsigned int id, unsigned int val)
{
	unsigned n = id >> ICFGR_SHIFT;
	GICD_WRITE32(GICD_ICFGR + (n << 2), val);
}

/*
 * Accessor to write the GIC Distributor NSACR corresponding to the
 * interrupt `id`, 16 interrupt IDs at a time.
 */
void gicd_write_nsacr(unsigned int id, unsigned int val)
{
	unsigned n = id >> NSACR_SHIFT;
	GICD_WRITE32(GICD_NSACR + (n << 2), val);
}

/*
 * Accessor to read the GIC Distributor IGRPMODR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
unsigned int gicd_read_igrpmodr(unsigned int id)
{
	unsigned n = id >> IGRPMODR_SHIFT;
	return GICD_READ32(GICD_IGRPMODR + (n << 2));
}

/*
 * Accessor to write the GIC Distributor IGRPMODR corresponding to the
 * interrupt `id`, 32 interrupt IDs at a time.
 */
void gicd_write_igrpmodr(unsigned int id, unsigned int val)
{
	unsigned n = id >> IGRPMODR_SHIFT;
	GICD_WRITE32(GICD_IGRPMODR + (n << 2), val);
}

/*
 * Accessor to get the bit corresponding to interrupt ID
 * in GIC Distributor IGRPMODR.
 */
unsigned int gicd_get_igrpmodr(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
	unsigned int reg_val = gicd_read_igrpmodr(id);

	return (reg_val >> bit_num) & 0x1;
}

/*
 * Accessor to set the bit corresponding to interrupt ID
 * in GIC Distributor IGRPMODR.
 */
void gicd_set_igrpmodr(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
	unsigned int reg_val = gicd_read_igrpmodr(id);

	gicd_write_igrpmodr(id, reg_val | (1 << bit_num));
}

/*
 * Accessor to clear the bit corresponding to interrupt ID
 * in GIC Distributor IGRPMODR.
 */
void gicd_clr_igrpmodr(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
	unsigned int reg_val = gicd_read_igrpmodr(id);

	gicd_write_igrpmodr(id, reg_val & ~(1 << bit_num));
}

/*
 * Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the
 * interrupt `id`, 4 interrupts IDs at a time.
 */
unsigned int gicr_read_ipriorityr(unsigned int id)
{
	unsigned n = id >> IPRIORITYR_SHIFT;
	return GICR_READ32(GICR_IPRIORITYR + (n << 2));
}

/*
 * Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the
 * interrupt `id`, 4 interrupts IDs at a time.
 */
void gicr_write_ipriorityr(unsigned int id, unsigned int val)
{
	unsigned n = id >> IPRIORITYR_SHIFT;
	GICR_WRITE32(GICR_IPRIORITYR + (n << 2), val);
}

/*
 * Accessor to get the bit corresponding to interrupt ID
 * from GIC Re-distributor IGROUPR0.
 */
unsigned int gicr_get_igroupr0(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
	unsigned int reg_val = GICR_READ32(GICR_IGROUPR0);

	return (reg_val >> bit_num) & 0x1;
}

/*
 * Accessor to set the bit corresponding to interrupt ID
 * in GIC Re-distributor IGROUPR0.
 */
void gicr_set_igroupr0(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
	unsigned int reg_val = GICR_READ32(GICR_IGROUPR0);

	GICR_WRITE32(GICR_IGROUPR0, reg_val | (1 << bit_num));
}

/*
 * Accessor to clear the bit corresponding to interrupt ID
 * in GIC Re-distributor IGROUPR0.
 */
void gicr_clr_igroupr0(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
	unsigned int reg_val = GICR_READ32(GICR_IGROUPR0);

	GICR_WRITE32(GICR_IGROUPR0, reg_val & ~(1 << bit_num));
}

/*
 * Accessor to get the bit corresponding to interrupt ID
 * from GIC Re-distributor IGRPMODR0.
 */
unsigned int gicr_get_igrpmodr0(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
	unsigned int reg_val = GICR_READ32(GICR_IGRPMODR0);

	return (reg_val >> bit_num) & 0x1;
}

/*
 * Accessor to set the bit corresponding to interrupt ID
 * in GIC Re-distributor IGRPMODR0.
 */
void gicr_set_igrpmodr0(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
	unsigned int reg_val = GICR_READ32(GICR_IGRPMODR0);

	GICR_WRITE32(GICR_IGRPMODR0, reg_val | (1 << bit_num));
}

/*
 * Accessor to clear the bit corresponding to interrupt ID
 * in GIC Re-distributor IGRPMODR0.
 */
void gicr_clr_igrpmodr0(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
	unsigned int reg_val = GICR_READ32(GICR_IGRPMODR0);

	GICR_WRITE32(GICR_IGRPMODR0, reg_val & ~(1 << bit_num));
}

/*
 * Accessor to set the bit corresponding to interrupt ID
 * in GIC Re-distributor ISENABLER0.
 */
void gicr_set_isenabler0(unsigned int id)
{
	unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);

	GICR_WRITE32(GICR_ISENABLER0, (1 << bit_num));
}

/*
 * Accessor to set the byte corresponding to interrupt ID
 * in GIC Re-distributor IPRIORITYR.
 */
void gicr_set_ipriorityr(unsigned int id, unsigned int pri)
{
	GICD_WRITE8(GICR_IPRIORITYR + id, pri & GIC_PRI_MASK);
}

/*******************************************************************************
 * GIC Distributor functions for accessing the GIC registers
 * corresponding to a single interrupt ID. These functions use bitwise
 * operations or appropriate register accesses to modify or return
 * the bit-field corresponding the single interrupt ID.
 ******************************************************************************/
unsigned int gicd_get_igroupr(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
	unsigned int reg_val = gicd_read_igroupr(id);

	return (reg_val >> bit_num) & 0x1;
}

void gicd_set_igroupr(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
	unsigned int reg_val = gicd_read_igroupr(id);

	gicd_write_igroupr(id, reg_val | (1 << bit_num));
}

void gicd_clr_igroupr(unsigned int id)
{
	unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
	unsigned int reg_val = gicd_read_igroupr(id);

	gicd_write_igroupr(id, reg_val & ~(1 << bit_num));
}

void gicd_set_isenabler(unsigned int id)
{
	unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);

	gicd_write_isenabler(id, (1 << bit_num));
}

void gicd_set_icenabler(unsigned int id)
{
	unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1);

	gicd_write_icenabler(id, (1 << bit_num));
}

void gicd_set_ispendr(unsigned int id)
{
	unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);

	gicd_write_ispendr(id, (1 << bit_num));
}

void gicd_set_icpendr(unsigned int id)
{
	unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);

	gicd_write_icpendr(id, (1 << bit_num));
}

void gicd_set_isactiver(unsigned int id)
{
	unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);

	gicd_write_isactiver(id, (1 << bit_num));
}

void gicd_set_icactiver(unsigned int id)
{
	unsigned bit_num = id & ((1 << ICACTIVER_SHIFT) - 1);

	gicd_write_icactiver(id, (1 << bit_num));
}

void gicd_set_ipriorityr(unsigned int id, unsigned int pri)
{
	GICD_WRITE8(GICD_IPRIORITYR + id, pri & GIC_PRI_MASK);
}


/******************************************************************************
 * This function marks the core as awake in the re-distributor and
 * ensures that the interface is active.
 *****************************************************************************/
void gicv3_rdistif_mark_core_awake(void)
{
	/*
	 * The WAKER_PS_BIT should be changed to 0
	 * only when WAKER_CA_BIT is 1.
	 */
	//assert(GICR_READ32(GICR_WAKER) & WAKER_CA_BIT);

	/* Mark the connected core as awake */
	GICR_WRITE32(GICR_WAKER, GICR_READ32(GICR_WAKER) & ~WAKER_PS_BIT);

	/* Wait till the WAKER_CA_BIT changes to 0 */
	while (GICR_READ32(GICR_WAKER) & WAKER_CA_BIT)
		;
}

/******************************************************************************
 * This function marks the core as asleep in the re-distributor and ensures
 * that the interface is quiescent.
 *****************************************************************************/
void gicv3_rdistif_mark_core_asleep(void)
{
	/* Mark the connected core as asleep */
	GICR_WRITE32(GICR_WAKER, GICR_READ32(GICR_WAKER) | WAKER_PS_BIT);

	/* Wait till the WAKER_CA_BIT changes to 1 */
	while (!(GICR_READ32(GICR_WAKER) & WAKER_CA_BIT))
		;
}

/*******************************************************************************
 * Helper function to configure the default attributes of SPIs.
 ******************************************************************************/
void gicv3_spis_configure_defaults(void)
{
	unsigned int index, num_ints;

	num_ints = GICD_READ32(GICD_TYPER);
	num_ints &= TYPER_IT_LINES_NO_MASK;
	num_ints = (num_ints + 1) << 5;

	/*
	 * Treat all SPIs as G1NS by default. The number of interrupts is
	 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
	 */
	for (index = MIN_SPI_ID; index < num_ints; index += 32)
		GICD_WRITE32(GICD_IGROUPR + ((index >> IGROUPR_SHIFT) << 2), ~0U);

	/* Setup the default SPI priorities doing four at a time */
	for (index = MIN_SPI_ID; index < num_ints; index += 4)
		GICD_WRITE32(GICD_IPRIORITYR + ((index >> IPRIORITYR_SHIFT) << 2), GICD_IPRIORITYR_DEF_VAL);

	/*
	 * Treat all SPIs as level triggered by default, write 16 at
	 * a time
	 */
	for (index = MIN_SPI_ID; index < num_ints; index += 16)
		GICD_WRITE32(GICD_ICFGR + ((index >> ICFGR_SHIFT) << 2),0);
}

/*******************************************************************************
 * Helper function to configure secure G0 and G1S SPIs.
 ******************************************************************************/
void gicv3_secure_spis_configure(unsigned int num_ints,
				     const unsigned int *sec_intr_list,
				     unsigned int int_grp)
{
	unsigned int index, irq_num;
	unsigned long long gic_affinity_val;

	//assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0));
	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
	//assert(num_ints ? (uintptr_t)sec_intr_list : 1);

	for (index = 0; index < num_ints; index++) {
		irq_num = sec_intr_list[index];
		if (irq_num >= MIN_SPI_ID) {

			/* Configure this interrupt as a secure interrupt */
			gicd_clr_igroupr(irq_num);

			/* Configure this interrupt as G0 or a G1S interrupt */
			if (int_grp == INTR_GROUP1S)
				gicd_set_igrpmodr(irq_num);
			else
				gicd_clr_igrpmodr(irq_num);

			/* Set the priority of this interrupt */
			gicd_set_ipriorityr(irq_num, GIC_HIGHEST_SEC_PRIORITY);

			/* Target SPIs to the primary CPU */
			gic_affinity_val =
				gicd_irouter_val_from_mpidr(read_mpidr(), 0);
			//assert(irq_num >= MIN_SPI_ID);
			GICD_WRITE32(GICD_IROUTER + (irq_num << 3), gic_affinity_val);

			/* Enable this interrupt */
			gicd_set_isenabler(irq_num);
		}
	}

}

/*******************************************************************************
 * Helper function to configure the default attributes of SPIs.
 ******************************************************************************/
void gicv3_ppi_sgi_configure_defaults(void)
{
	unsigned int index;

	/*
	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
	 * more scalable approach as it avoids clearing the enable bits in the
	 * GICD_CTLR
	 */
	GICR_WRITE32(GICR_ICENABLER0, ~0);
	gicr_wait_for_pending_write();

	/* Treat all SGIs/PPIs as G1NS by default. */
	GICR_WRITE32(GICR_IGROUPR0, ~0U);

	/* Setup the default PPI/SGI priorities doing four at a time */
	for (index = 0; index < MIN_SPI_ID; index += 4)
		gicr_write_ipriorityr(index,
				      GICD_IPRIORITYR_DEF_VAL);

	/* Configure all PPIs as level triggered by default */
	GICR_WRITE32(GICR_ICFGR1, 0);
}

/*******************************************************************************
 * Helper function to configure secure G0 and G1S SPIs.
 ******************************************************************************/
void gicv3_secure_ppi_sgi_configure(unsigned int num_ints,
					const unsigned int *sec_intr_list,
					unsigned int int_grp)
{
	unsigned int index, irq_num;

	//assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0));
	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
	//assert(num_ints ? (uintptr_t)sec_intr_list : 1);

	for (index = 0; index < num_ints; index++) {
		irq_num = sec_intr_list[index];
		if (irq_num < MIN_SPI_ID) {

			/* Configure this interrupt as a secure interrupt */
			gicr_clr_igroupr0(irq_num);

			/* Configure this interrupt as G0 or a G1S interrupt */
			if (int_grp == INTR_GROUP1S)
				gicr_set_igrpmodr0(irq_num);
			else
				gicr_clr_igrpmodr0(irq_num);

			/* Set the priority of this interrupt */
			gicr_set_ipriorityr(irq_num,
					    GIC_HIGHEST_SEC_PRIORITY);

			/* Enable this interrupt */
			gicr_set_isenabler0(irq_num);
		}
	}
}

/*******************************************************************************
 * This function initialises the GIC distributor interface based upon the data
 * provided by the platform while initialising the driver.
 ******************************************************************************/
void gicv3_distif_init(void)
{
	unsigned int bitmap = 0;

	/*
	 * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
	 * the ARE_S bit. The Distributor might generate a system error
	 * otherwise.
	 */
	GICD_WRITE32(GICD_CTLR, CTLR_ENABLE_G0_BIT |CTLR_ENABLE_G1S_BIT |CTLR_ENABLE_G1NS_BIT);
	gicd_wait_for_pending_write();

	/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
	GICD_WRITE32(GICD_CTLR, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT);
	gicd_wait_for_pending_write();

	/* Set the default attribute of all SPIs */
	gicv3_spis_configure_defaults();

	/* Configure the G1S SPIs */
	gicv3_secure_spis_configure(ARRAY_SIZE(g1s_interrupt_array),
				g1s_interrupt_array,
				INTR_GROUP1S);
	bitmap |= CTLR_ENABLE_G1S_BIT;

	/* Enable the secure SPIs now that they have been configured */
	GICD_WRITE32(GICD_CTLR,bitmap);
	gicd_wait_for_pending_write();
}

/*******************************************************************************
 * This function initialises the GIC Redistributor interface of the calling CPU
 * (identified by the 'proc_num' parameter) based upon the data provided by the
 * platform while initialising the driver.
 ******************************************************************************/
void gicv3_rdistif_init(void)
{
	uintptr_t gicr_base;

	/* Set the default attribute of all SGIs and PPIs */
	gicv3_ppi_sgi_configure_defaults();

	/* Configure the G1S SGIs/PPIs */
	gicv3_secure_ppi_sgi_configure(ARRAY_SIZE(g1s_interrupt_array),
				g1s_interrupt_array,
				INTR_GROUP1S);
}

/*******************************************************************************
 * This function enables the GIC CPU interface of the calling CPU using only
 * system register accesses.
 ******************************************************************************/
void gicv3_cpuif_enable(void)
{
	unsigned int scr_el3;
	unsigned int icc_sre_el3;

	/* Mark the connected core as awake */
	gicv3_rdistif_mark_core_awake();

	write_icc_sre_el1(ICC_SRE_SRE_BIT);
	isb();

	/* Program the idle priority in the PMR */
	write_icc_pmr_el1(GIC_PRI_MASK);

	/* Enable Group0 interrupts */
	write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT);

	/* Write the secure ICC_SRE_EL1 register */
	write_icc_sre_el1(ICC_SRE_SRE_BIT);
	isb();
}
#endif
static void GIC_EnableIrq(UINT32 u4Vector)
{
        UINT32 u4Irq = u4Vector + SPI_OFFSET;

        UINT32 u4Mask = 1 << (u4Irq % 32);

        GICD_WRITE32(GIC_DIST_ENABLE_SET + (u4Irq / 32) * 4, u4Mask);
}

static void GIC_DisableIrq(UINT32 u4Vector)
{
        UINT32 u4Irq = u4Vector + SPI_OFFSET;

        UINT32 u4Mask = 1 << (u4Irq % 32);

        GICD_WRITE32(GIC_DIST_ENABLE_CLEAR + (u4Irq / 32) * 4, u4Mask);
}

static void GIC_ClearIrq(UINT32 u4Vector)
{
        UINT32 u4Irq = u4Vector + SPI_OFFSET;

        //UINT32 u4Mask = 1 << (u4Irq % 32);
#ifdef CC_ARM_GIC_V3
        write_eoi_el1(u4Irq);
#else
        GICC_WRITE32(GIC_CPU_EOI, u4Irq);
#endif
}

static BOOL GIC_IsIrqEnabled(UINT32 u4Vector)
{
        UINT32 u4Irq = u4Vector + SPI_OFFSET;

        UINT32 u4Mask = 1 << (u4Irq % 32);

    return ((GICD_READ32(GIC_DIST_ENABLE_SET + (u4Irq / 32) * 4) & u4Mask) != 0)?TRUE:FALSE;
}
static BOOL GIC_IsIrqPending(UINT32 u4Vector)
 {
        UINT32 u4Irq = u4Vector + SPI_OFFSET;
        UINT32 u4Mask = 1 << (u4Irq % 32);

    return ((GICD_READ32(GIC_DIST_PENDING_SET + (u4Irq / 32) * 4) & u4Mask) != 0)?TRUE:FALSE;
}
static void GIC_ClearDisableIrq(void)
{
    UINT32 i=0;
    GICD_WRITE32(GIC_DIST_CTRL, 0);
    //disable all intrrupt
    for (i = 32; i < GIC_IRQS; i += 32)
        {
                GICD_WRITE32(GIC_DIST_ENABLE_CLEAR + i * 4 / 32, 0xffffffff);
        }
    //clear pending interrupt
    for (i = 32; i < GIC_IRQS; i += 32)
        {
                GICD_WRITE32(GIC_DIST_PENDING_CLEAR + i * 4 / 32, 0xffffffff);
        }

}
#endif /* CC_ARM_GIC */

//-----------------------------------------------------------------------------
/** _BimIsVectorValid() to check the vector value is valid.
 *  @param u4Vector the checking vector value.
 */
//-----------------------------------------------------------------------------
static BOOL _BimIsVectorValid(UINT32 u4Vector)
{
    return (u4Vector <= MAX_IRQ_VECTOR);
}


//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
#ifdef CC_ARM_GIC
void GIC_Init(void)
{
#ifdef CC_ARM_GIC_V3
	gicv3_distif_init();
	gicv3_rdistif_init();
	gicv3_cpuif_enable();
#else
	UINT32 i;

	//
	// Init gic distributor
	//
	GICD_WRITE32(GIC_DIST_CTRL, 0);

	// Set all global interrupts to be level triggered, active low.
	for (i = 32; i < GIC_IRQS; i += 16)
	{
		GICD_WRITE32(GIC_DIST_CONFIG + i * 4 / 16, 0);
	}

	// Set all global interrupts to CPU core 0 only.
	for (i = 32; i < GIC_IRQS; i += 4)
	{
		GICD_WRITE32(GIC_DIST_TARGET + i * 4 / 4, 0x01010101);
	}

	// Set priority on all global interrupts.
	for (i = 32; i < GIC_IRQS; i += 4)
	{
		GICD_WRITE32(GIC_DIST_PRI + i * 4 / 4, 0xa0a0a0a0);
	}
	#ifdef CC_FIQ_SUPPORT
	// set group to id 1, expect  gpio irq //0xf1001080
		for (i = 32; i < GIC_IRQS; i += 32)
	{
		GICD_WRITE32(GIC_DIST_IGROUPR + i * 4 / 32, 0xffffffff);

		#if defined(CC_MT5882)|| defined(CC_MT5883)
		//set  ID=33 To fiq
		if(i==96)
		{
			GICD_WRITE32(GIC_DIST_IGROUPR + i * 4 / 32, 0xfffffff7);
		}
		#else   //defined(CC_MT5891)
		//set  ID=35 To fiq
		if(i==192)
		{
			GICD_WRITE32(GIC_DIST_IGROUPR + i * 4 / 32, 0xfff000ff);
		}
		#endif
	}

    #endif
	// Disable all interrupts.  Leave the PPI and SGIs alone as these enables are banked registers.
	for (i = 32; i < GIC_IRQS; i += 32)
	{
		GICD_WRITE32(GIC_DIST_ENABLE_CLEAR + i * 4 / 32, 0xffffffff);
	}
#ifdef CC_FIQ_SUPPORT
	GICD_WRITE32(GIC_DIST_CTRL, 3);
#else
    GICD_WRITE32(GIC_DIST_CTRL, 1);
#endif
	// Deal with the banked PPI and SGI interrupts - disable all PPI interrupts, ensure all SGI interrupts are enabled.
	GICD_WRITE32(GIC_DIST_ENABLE_CLEAR, 0xffff0000);
	GICD_WRITE32(GIC_DIST_ENABLE_SET, 0x0000ffff);

	// Set priority on PPI and SGI interrupts
	for (i = 0; i < 32; i += 4)
	{
		GICD_WRITE32(GIC_DIST_PRI + i * 4 / 4, 0xa0a0a0a0);
	}

	GICC_WRITE32(GIC_CPU_PRIMASK, 0xf0);
	#ifdef CC_FIQ_SUPPORT
	//0xf1002000
	GICC_WRITE32(GIC_CPU_CTRL, 0xb);
	#else
	GICC_WRITE32(GIC_CPU_CTRL, 1);
	#endif
#endif
}
#endif /* CC_ARM_GIC */

//-----------------------------------------------------------------------------
/** BIM_EnableIrq() Enable the interrupt of a given vector
 *  @param u4Vector: The vector
 *  @retval TRUE: Succeed
 *  @retval FALSE: Fail
 */
//-----------------------------------------------------------------------------
BOOL BIM_EnableIrq(UINT32 u4Vector)
{
#ifndef CC_NO_BIM_INTR
	#ifndef CC_UBOOT
    UINT32 u4State;
	#endif /* CC_UBOOT */
    UINT32 u4Irq;
#endif
    if (!_BimIsVectorValid(u4Vector))
    {
        return FALSE;
    }
#ifndef CC_NO_BIM_INTR
    #ifdef CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC3_BASE)
    {
        u4Irq = _MISC3IRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_REG32(REG_MISC3_IRQEN) |= u4Irq;
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */
    } else
    #endif // CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC2_BASE)
    {
        u4Irq = _MISC2IRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_REG32(REG_MISC2_IRQEN) |= u4Irq;
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */
    }
    else if (u4Vector > VECTOR_MISC)
    {
        u4Irq = _MISCIRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_REG32(REG_MISC_IRQEN) |= u4Irq;
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */
    }
    else
    {
        u4Irq = _IRQ(u4Vector);

        // Should be in critical section to avoid race condition
    	#ifndef CC_UBOOT
        u4State = HalCriticalStart();
    	#endif /* CC_UBOOT */
        BIM_REG32(REG_IRQEN) |= u4Irq;
    	#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
    	#endif /* CC_UBOOT */
    }
#endif
	#ifdef CC_ARM_GIC
	GIC_EnableIrq(u4Vector);
	#endif

    return TRUE;
}


//-----------------------------------------------------------------------------
/** BIM_DisableIrq() Disable the interrupt of a given vector
 *  @param u4Vector: The vector
 *  @retval TRUE: Succeed
 *  @retval FALSE: Fail
 */
//-----------------------------------------------------------------------------
BOOL BIM_DisableIrq(UINT32 u4Vector)
{
#ifndef CC_NO_BIM_INTR
	#ifndef CC_UBOOT
    UINT32 u4State;
	#endif /* CC_UBOOT */
    UINT32 u4Irq;
#endif
    if (!_BimIsVectorValid(u4Vector))
    {
        return FALSE;
    }

	#ifdef CC_ARM_GIC
	GIC_DisableIrq(u4Vector);
	#endif
#ifndef CC_NO_BIM_INTR
    #ifdef CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC3_BASE)
    {
        u4Irq = _MISC3IRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_REG32(REG_MISC3_IRQEN) &= ~u4Irq;
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */

        return TRUE;
    } else
    #endif // CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC2_BASE)
    {
        u4Irq = _MISC2IRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_REG32(REG_MISC2_IRQEN) &= ~u4Irq;
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */

        return TRUE;
    }
    else if (u4Vector > VECTOR_MISC)
    {
        u4Irq = _MISCIRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_REG32(REG_MISC_IRQEN) &= ~u4Irq;
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */

        return TRUE;
    }
    else
    {
        u4Irq = _IRQ(u4Vector);

        // Should be in critical section to avoid race condition
    	#ifndef CC_UBOOT
        u4State = HalCriticalStart();
    	#endif /* CC_UBOOT */
        BIM_REG32(REG_IRQEN) &= ~u4Irq;
    	#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
    	#endif /* CC_UBOOT */
    }
#endif
    return TRUE;
}


//-----------------------------------------------------------------------------
/** BIM_IsIrqEnabled Query if the interrupt of a given vector is enabled
 *  @param u4Vector: The vector
 *  @retval TRUE: Interrupt is enabled
 *  @retval FALSE: Interrupt is disabled, or the vector is invalid
 */
//-----------------------------------------------------------------------------
BOOL BIM_IsIrqEnabled(UINT32 u4Vector)
{
#ifdef CC_ARM_GIC
    return GIC_IsIrqEnabled(u4Vector);
#else
    UINT32 u4State;

    if (!_BimIsVectorValid(u4Vector))
    {
        return FALSE;
    }

    #ifdef CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC3_BASE)
    {
        u4State = BIM_READ32(REG_MISC3_IRQEN);
        return (u4State & _MISC3IRQ(u4Vector)) != 0;
    } else
    #endif // CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC2_BASE)
    {
        u4State = BIM_READ32(REG_MISC2_IRQEN);
        return (u4State & _MISC2IRQ(u4Vector)) != 0;
    }
    else if (u4Vector > VECTOR_MISC)
    {
        u4State = BIM_READ32(REG_MISC_IRQEN);

        return (u4State & _MISCIRQ(u4Vector)) != 0;
    }

    u4State = BIM_READ32(REG_IRQEN);

    return (u4State & _IRQ(u4Vector)) != 0;
#endif // CC_ARM_GIC
}


//-----------------------------------------------------------------------------
/** BIM_IsIrqPending Query if the interrupt of a given vector is pending
 *  @param u4Vector: The vector
 *  @retval TRUE: The interrupt is pending
 *  @retval FALSE: The interrupt is not asserted, or the given vector is invalid
 */
//-----------------------------------------------------------------------------
BOOL BIM_IsIrqPending(UINT32 u4Vector)
{
#ifdef CC_ARM_GIC
	return GIC_IsIrqPending(u4Vector);
#else
    UINT32 u4State;
    if (!_BimIsVectorValid(u4Vector))
    {
        return FALSE;
    }

    #ifdef CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC3_BASE)
    {
        u4State = BIM_READ32(REG_MISC3_IRQST);
        return (u4State & _MISC3IRQ(u4Vector)) != 0;
    } else
    #endif // CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC2_BASE)
    {
        u4State = BIM_READ32(REG_MISC2_IRQST);
        return (u4State & _MISC2IRQ(u4Vector)) != 0;
    }
    else if (u4Vector > VECTOR_MISC)
    {
        u4State = BIM_READ32(REG_MISC_IRQST);

        return (u4State & _MISCIRQ(u4Vector)) != 0;
    }

    u4State = BIM_READ32(REG_IRQST);

    return (u4State & _IRQ(u4Vector)) != 0;
#endif
}


//-----------------------------------------------------------------------------
/** BIM_ClearIrq() Clear the pending interrupt of a given vector
 *  @param u4Vector: The vector
 *  @retval TRUE: Succeed
 *  @retval FALSE: Fail
 */
//-----------------------------------------------------------------------------
BOOL BIM_ClearIrq(UINT32 u4Vector)
{
#ifndef CC_NO_BIM_INTR
    UINT32 u4Irq;
	#ifndef CC_UBOOT
    UINT32 u4State;
	#endif /* CC_UBOOT */
#endif

    if (!_BimIsVectorValid(u4Vector))
    {
        return FALSE;
    }
#ifndef CC_NO_BIM_INTR
    #ifdef CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC3_BASE)
    {
        u4Irq = _MISC3IRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_WRITE32(REG_MISC3_IRQCLR, u4Irq);
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */
    } else
    #endif // CC_VECTOR_HAS_MISC3
    if (u4Vector >= VECTOR_MISC2_BASE)
    {
        u4Irq = _MISC2IRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_WRITE32(REG_MISC2_IRQCLR, u4Irq);
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */
    }
    else if (u4Vector > VECTOR_MISC)
    {
        u4Irq = _MISCIRQ(u4Vector);
		#ifndef CC_UBOOT
        u4State = HalCriticalStart();
		#endif /* CC_UBOOT */
        BIM_WRITE32(REG_MISC_IRQCLR, u4Irq);
		#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
		#endif /* CC_UBOOT */
    }
    else
    {
        u4Irq = _IRQ(u4Vector);

    	#ifndef CC_UBOOT
        u4State = HalCriticalStart();
    	#endif /* CC_UBOOT */
        BIM_WRITE32(REG_IRQCL, u4Irq);
    	#ifndef CC_UBOOT
        HalCriticalEnd(u4State);
    	#endif /* CC_UBOOT */
    }
#endif
	#ifdef CC_ARM_GIC
	GIC_ClearIrq(u4Vector);
	#endif

    return TRUE;
}

#ifndef CC_SECURE_WORLD
//-----------------------------------------------------------------------------
/** BIM_Set7Seg() Set the 7-segment display LED value.
 *  @param u4Value the last 4 digits of u4Value will display on the 7-Seg LED.
 */
//-----------------------------------------------------------------------------
void BIM_Set7Seg(UINT32 u4Value)
{
    // no support in 5387
    //BIM_WRITE32(REG_RW_SEG7_DATA, u4Value);
}
void BIM_ClearDisableIrq(void)
{
#ifdef CC_ARM_GIC
	return GIC_ClearDisableIrq();
#endif
}
//-----------------------------------------------------------------------------
/** BIM_GetOscillator() Get ring oscillator raw value.
 *  @retval return the ring oscillator raw value.
 */
//-----------------------------------------------------------------------------
UINT32 BIM_GetOscillator()
{
    BIM_WRITE32(REG_RW_ROSCCTL, ROSC_CLR);
    BIM_WRITE32(REG_RW_ROSCCTL, ROSC_SEL);
    BIM_WRITE32(REG_RW_ROSCCTL, (ROSC_SEL | ROSC_TRIGGER));
    HAL_Delay_us(10000);
    return BIM_READ32(REG_RO_ROSCCNT);
}

//-----------------------------------------------------------------------------
/** BIM_LockModifyReg32() Read/and/or/Write register with lock held
 *  to prevent modify register from other threads.
 */
//-----------------------------------------------------------------------------
void BIM_LockModifyReg32(UINT32 reg, UINT32 mask, UINT32 setVal)
{
    UINT32 u4State, u4Val;

	#ifndef CC_UBOOT
    u4State = HalCriticalStart();
	#endif /* CC_UBOOT */
    u4Val = BIM_READ32(reg);
    u4Val &= mask;
    u4Val |= setVal;
    BIM_WRITE32(reg, u4Val);
	#ifndef CC_UBOOT
    HalCriticalEnd(u4State);
	#endif /* CC_UBOOT */
}

#if defined(CC_SUPPORT_STR_CORE_OFF) && !defined(CC_MTK_LOADER) && !defined(CC_UBOOT)
//-----------------------------------------------------------------------------
/** BIM_pm_suspend()
 *  Suspend function, save IRQ enable setting.
 */
//-----------------------------------------------------------------------------
static UINT32 aBimSuspendSaves[5];
void BIM_pm_suspend(void)
{
    aBimSuspendSaves[0] = BIM_REG32(REG_RW_MISC);
    aBimSuspendSaves[1] = BIM_REG32(REG_IRQEN);
#ifndef CC_NO_BIM_INTR
    aBimSuspendSaves[2] = BIM_REG32(REG_MISC_IRQEN);
	#ifdef REG_MISC2_IRQEN
    aBimSuspendSaves[3] = BIM_REG32(REG_MISC2_IRQEN);
	#endif
    #ifdef REG_MISC3_IRQEN
	aBimSuspendSaves[4] = BIM_REG32(REG_MISC3_IRQEN);
    #endif
#endif
}

//-----------------------------------------------------------------------------
/** BIM_pm_suspend()
 *  Resume function, restore IRQ settings
 */
//-----------------------------------------------------------------------------
void BIM_pm_resume(void)
{
    BIM_REG32(REG_RW_MISC) = aBimSuspendSaves[0];
    BIM_REG32(REG_IRQEN) = aBimSuspendSaves[1];
#ifndef CC_NO_BIM_INTR
    BIM_REG32(REG_MISC_IRQEN) = aBimSuspendSaves[2];
	#ifdef REG_MISC2_IRQEN
    BIM_REG32(REG_MISC2_IRQEN) = aBimSuspendSaves[3];
	#endif
#ifdef REG_MISC3_IRQEN
    BIM_REG32(REG_MISC3_IRQEN) = aBimSuspendSaves[4];
#endif
#endif
}
#endif /* CC_SUPPORT_STR_CORE_OFF && !loader && !uboot */
#endif
#endif /*CC_MTK_PRELOADER*/
