/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSBSPsSPARCLEON3 * * @brief This header file provides interfaces used by the BSP implementation. */ /* * Copyright (C) 2014, 2021 embedded brains GmbH (http://www.embedded-brains.de) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * 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 OWNER 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. */ #ifndef _BSP_LEON3_H #define _BSP_LEON3_H #include #include #include #include #include #include #if !defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER) #include #endif struct ambapp_dev; #ifdef __cplusplus extern "C" { #endif /** * @addtogroup RTEMSBSPsSPARCLEON3 * * @{ */ /** * @brief This object provides the index of the boot processor. * * This object should be read-only after initialization. */ extern uint32_t LEON3_Cpu_Index; /** * @brief Sets %asr19 to zero to enter the power-down mode of the processor in * an infinite loop. */ RTEMS_NO_RETURN void leon3_power_down_loop( void ); /** * @brief This constant represents the flush instruction cache flag of the LEON * cache control register. */ #define LEON3_REG_CACHE_CTRL_FI 0x00200000U /** * @brief This constant represents the data cache snooping enable flag of the * LEON cache control register. */ #define LEON3_REG_CACHE_CTRL_DS 0x00800000U /** * @brief Sets the ASI 0x2 system register value. * * @param addr is the address of the ASI 0x2 system register. * * @param val is the value to set. */ static inline void leon3_set_system_register( uint32_t addr, uint32_t val ) { __asm__ volatile( "sta %1, [%0] 2" : : "r" ( addr ), "r" ( val ) ); } /** * @brief Gets the ASI 0x2 system register value. * * @param addr is the address of the ASI 0x2 system register. * * @return Returns the register value. */ static inline uint32_t leon3_get_system_register( uint32_t addr ) { uint32_t val; __asm__ volatile( "lda [%1] 2, %0" : "=r" ( val ) : "r" ( addr ) ); return val; } /** * @brief Sets the LEON cache control register value. * * @param val is the value to set. */ static inline void leon3_set_cache_control_register( uint32_t val ) { leon3_set_system_register( 0x0, val ); } /** * @brief Gets the LEON cache control register value. * * @return Returns the register value. */ static inline uint32_t leon3_get_cache_control_register( void ) { return leon3_get_system_register( 0x0 ); } /** * @brief Checks if the data cache snooping is enabled. * * @return Returns true, if the data cache snooping is enabled, otherwise * false. */ static inline bool leon3_data_cache_snooping_enabled( void ) { return ( leon3_get_cache_control_register() & LEON3_REG_CACHE_CTRL_DS ) != 0; } /** * @brief Gets the LEON instruction cache configuration register value. * * @return Returns the register value. */ static inline uint32_t leon3_get_inst_cache_config_register( void ) { return leon3_get_system_register( 0x8 ); } /** * @brief Gets the LEON data cache configuration register value. * * @return Returns the register value. */ static inline uint32_t leon3_get_data_cache_config_register( void ) { return leon3_get_system_register( 0xc ); } /** * @brief This lock serializes the interrupt controller access. */ extern rtems_interrupt_lock LEON3_IrqCtrl_Lock; /** * @brief Acquires the interrupt controller lock. * * @param[out] _lock_context is the lock context. */ #define LEON3_IRQCTRL_ACQUIRE( _lock_context ) \ rtems_interrupt_lock_acquire( &LEON3_IrqCtrl_Lock, _lock_context ) /** * @brief Releases the interrupt controller lock. * * @param[in, out] _lock_context is the lock context. */ #define LEON3_IRQCTRL_RELEASE( _lock_context ) \ rtems_interrupt_lock_release( &LEON3_IrqCtrl_Lock, _lock_context ) /** * @brief This pointer provides the IRQ(A)MP register block address. */ #if defined(LEON3_IRQAMP_BASE) #define LEON3_IrqCtrl_Regs ((irqamp *) LEON3_IRQAMP_BASE) #else extern irqamp *LEON3_IrqCtrl_Regs; #endif /** * @brief This pointer provides the IRQ(A)MP device information block. */ extern struct ambapp_dev *LEON3_IrqCtrl_Adev; /** * @brief This object provides the interrupt number used to multiplex extended * interrupts or is zero if no extended interrupts are available. * * This object should be read-only after initialization. */ #if defined(LEON3_IRQAMP_EXTENDED_INTERRUPT) #define LEON3_IrqCtrl_EIrq LEON3_IRQAMP_EXTENDED_INTERRUPT #else extern uint32_t LEON3_IrqCtrl_EIrq; #endif /** * @brief Initializes the interrupt controller for the boot processor. * * @param[in, out] regs is the IRQ(A)MP register block address. */ void leon3_ext_irq_init( irqamp *regs ); /** * @brief Gets the processor count. * * @param[in] regs is the IRQ(A)MP register block address. * * @return Returns the processor count. */ static inline uint32_t leon3_get_cpu_count( const irqamp *regs ) { return IRQAMP_MPSTAT_NCPU_GET( grlib_load_32( ®s->mpstat ) ) + 1; } /** * @brief Acknowledges and maps extended interrupts if this feature is * available and the interrupt for extended interrupts is present. * * @param irq is the standard interrupt number. */ static inline uint32_t bsp_irq_fixup( uint32_t irq ) { uint32_t eirq; uint32_t cpu_self; if ( irq != LEON3_IrqCtrl_EIrq ) { return irq; } cpu_self = _LEON3_Get_current_processor(); eirq = grlib_load_32( &LEON3_IrqCtrl_Regs->pextack[ cpu_self ] ); eirq = IRQAMP_PEXTACK_EID_4_0_GET( eirq ); if ( eirq < 16 ) { return irq; } return eirq; } /** * @brief This constant defines the index of the GPTIMER timer used by the * clock driver. */ #if defined(RTEMS_MULTIPROCESSING) #define LEON3_CLOCK_INDEX \ ( rtems_configuration_get_user_multiprocessing_table() ? LEON3_Cpu_Index : 0 ) #else #define LEON3_CLOCK_INDEX 0 #endif /** * @brief This constant defines the index of the GPTIMER timer used by the * CPU counter if the CPU counter uses the GPTIMER. */ #if defined(RTEMS_SMP) #define LEON3_COUNTER_GPTIMER_INDEX ( LEON3_CLOCK_INDEX + 1 ) #else #define LEON3_COUNTER_GPTIMER_INDEX LEON3_CLOCK_INDEX #endif /** * @brief This constant defines the frequency set by the boot loader of the * first GPTIMER instance. * * We assume that a boot loader (usually GRMON) initialized the GPTIMER 0 to * run with 1MHz. This is used to determine all clock frequencies of the PnP * devices. See also ambapp_freq_init() and ambapp_freq_get(). */ #define LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER 1000000 /** * @brief This pointer provides the GPTIMER register block address. */ #if defined(LEON3_GPTIMER_BASE) #define LEON3_Timer_Regs ((gptimer *) LEON3_GPTIMER_BASE) #else extern gptimer *LEON3_Timer_Regs; #endif /** * @brief This pointer provides the GPTIMER device information block. */ extern struct ambapp_dev *LEON3_Timer_Adev; /** * @brief Gets the processor local bus frequency in Hz. * * @return Returns the frequency. */ static inline uint32_t leon3_processor_local_bus_frequency( void ) { #if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER) return ( grlib_load_32( &LEON3_Timer_Regs->sreload ) + 1 ) * LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER; #else /* * For simplicity, assume that the interrupt controller uses the processor * clock. This is at least true on the GR740. */ return ambapp_freq_get( ambapp_plb(), LEON3_IrqCtrl_Adev ); #endif } /** * @brief Gets the LEON up-counter low register (%ASR23) value. * * @return Returns the register value. */ static inline uint32_t leon3_up_counter_low( void ) { uint32_t asr23; __asm__ volatile ( "mov %%asr23, %0" : "=&r" (asr23) ); return asr23; } /** * @brief Gets the LEON up-counter high register (%ASR22) value. * * @return Returns the register value. */ static inline uint32_t leon3_up_counter_high(void) { uint32_t asr22; __asm__ volatile ( "mov %%asr22, %0" : "=&r" (asr22) ); return asr22; } /** * @brief Enables the LEON up-counter. */ static inline void leon3_up_counter_enable( void ) { __asm__ volatile ( "mov %g0, %asr22" ); } #if !defined(LEON3_HAS_ASR_22_23_UP_COUNTER) /** * @brief Checks if the LEON up-counter is available. * * The LEON up-counter must have been enabled. * * @return Returns true, if the LEON up-counter is available, otherwise false. */ static inline bool leon3_up_counter_is_available( void ) { return leon3_up_counter_low() != leon3_up_counter_low(); } #endif /** * @brief Gets the LEON up-counter frequency in Hz. * * @return Returns the frequency. */ static inline uint32_t leon3_up_counter_frequency( void ) { return leon3_processor_local_bus_frequency(); } /** * @brief This pointer provides the debug APBUART register block address. */ #if defined(LEON3_APBUART_BASE) #define leon3_debug_uart ((struct apbuart *) LEON3_APBUART_BASE) #else extern apbuart *leon3_debug_uart; #endif /** @} */ #ifdef __cplusplus } #endif #endif /* _BSP_LEON3_H */