Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:49

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsMicroblaze
0007  *
0008  * @brief MicroBlaze AXI Timer clock support
0009  */
0010 
0011 /*
0012  * Copyright (C) 2021 On-Line Applications Research Corporation (OAR)
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 #include <bsp/fatal.h>
0038 #include <bsp/timer.h>
0039 
0040 #include <rtems.h>
0041 #include <rtems/irq-extension.h>
0042 #include <rtems/timecounter.h>
0043 
0044 static rtems_timecounter_simple mblaze_tc;
0045 static volatile Microblaze_Timer *mblaze_timer;
0046 
0047 static uint32_t microblaze_tc_get( rtems_timecounter_simple *tc )
0048 {
0049   return mblaze_timer->tcr0;
0050 }
0051 
0052 static bool microblaze_tc_is_pending( rtems_timecounter_simple *tc )
0053 {
0054   return ( mblaze_timer->tcsr0 & MICROBLAZE_TIMER_TCSR0_T0INT ) != 0;
0055 }
0056 
0057 static uint32_t microblaze_tc_get_timecount( struct timecounter *tc )
0058 {
0059   return rtems_timecounter_simple_downcounter_get(
0060     tc,
0061     microblaze_tc_get,
0062     microblaze_tc_is_pending
0063   );
0064 }
0065 
0066 static void microblaze_clock_initialize( void )
0067 {
0068   mblaze_timer = (volatile Microblaze_Timer *) try_get_prop_from_device_tree(
0069     "xlnx,xps-timer-1.00.a",
0070     "reg",
0071     BSP_MICROBLAZE_FPGA_TIMER_BASE
0072   );
0073 
0074   /* Set load register to 0 */
0075   mblaze_timer->tlr0 = 0;
0076   /* Reset the timer and interrupt */
0077   mblaze_timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_T0INT | MICROBLAZE_TIMER_TCSR0_LOAD0;
0078   /* Release the reset */
0079   mblaze_timer->tcsr0 = 0;
0080   /*
0081    * Enable interrupt, auto reload mode, external interrupt signal,
0082    * and down counter
0083    */
0084   mblaze_timer->tcsr0 =  MICROBLAZE_TIMER_TCSR0_ARHT0 | MICROBLAZE_TIMER_TCSR0_ENIT0 |
0085                   MICROBLAZE_TIMER_TCSR0_GENT0 | MICROBLAZE_TIMER_TCSR0_UDT0;
0086 
0087   uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
0088   uint32_t counter_frequency_in_hz = try_get_prop_from_device_tree(
0089     "xlnx,xps-timer-1.00.a",
0090     "clock-frequency",
0091     BSP_MICROBLAZE_FPGA_TIMER_FREQUENCY
0092   );
0093   uint32_t counter_ticks_per_clock_tick =
0094     ( counter_frequency_in_hz * us_per_tick ) / 1000000;
0095 
0096   /* Set a reset value for the timer counter */
0097   mblaze_timer->tlr0 = counter_ticks_per_clock_tick;
0098   uint32_t control_status_reg = mblaze_timer->tcsr0;
0099   /* Load the reset value into the counter register */
0100   mblaze_timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_LOAD0;
0101   /* Enable the timer */
0102   mblaze_timer->tcsr0 = control_status_reg | MICROBLAZE_TIMER_TCSR0_ENT0;
0103 
0104   rtems_timecounter_simple_install(
0105     &mblaze_tc,
0106     counter_frequency_in_hz,
0107     counter_ticks_per_clock_tick,
0108     microblaze_tc_get_timecount
0109   );
0110 }
0111 
0112 static void microblaze_clock_at_tick( rtems_timecounter_simple *tc )
0113 {
0114   if ( ( mblaze_timer->tcsr0 & MICROBLAZE_TIMER_TCSR0_T0INT ) == 0 ) {
0115     return;
0116   }
0117   /* Clear the interrupt */
0118   mblaze_timer->tcsr0 |= MICROBLAZE_TIMER_TCSR0_T0INT;
0119 }
0120 
0121 static void microblaze_tc_tick( rtems_timecounter_simple *tc )
0122 {
0123   rtems_timecounter_simple_downcounter_tick(
0124     tc,
0125     microblaze_tc_get,
0126     microblaze_clock_at_tick
0127   );
0128 }
0129 
0130 static void microblaze_clock_handler_install( rtems_interrupt_handler isr )
0131 {
0132   rtems_status_code sc = RTEMS_SUCCESSFUL;
0133 
0134   uint32_t clock_irq_num = try_get_prop_from_device_tree(
0135     "xlnx,xps-timer-1.00.a",
0136     "interrupts",
0137     0
0138   );
0139 
0140   sc = rtems_interrupt_handler_install(
0141     clock_irq_num,
0142     "Clock",
0143     RTEMS_INTERRUPT_UNIQUE,
0144     isr,
0145     &mblaze_tc
0146   );
0147 
0148   if ( sc != RTEMS_SUCCESSFUL ) {
0149     bsp_fatal( MICROBLAZE_FATAL_CLOCK_IRQ_INSTALL );
0150   }
0151 }
0152 
0153 #define Clock_driver_support_initialize_hardware() microblaze_clock_initialize()
0154 #define Clock_driver_support_install_isr( isr ) \
0155   microblaze_clock_handler_install( isr )
0156 #define Clock_driver_timecounter_tick(arg) microblaze_tc_tick(arg)
0157 
0158 /* Include shared source clock driver code */
0159 #include "../../shared/dev/clock/clockimpl.h"