Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsPowerPCMPC55XX
0007  *
0008  * @brief Clock driver configuration.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2013 embedded brains GmbH & Co. KG
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/irq.h>
0039 
0040 #include <mpc55xx/regs.h>
0041 
0042 #include <rtems/timecounter.h>
0043 
0044 static rtems_timecounter_simple mpc55xx_tc;
0045 
0046 #if defined(MPC55XX_CLOCK_EMIOS_CHANNEL)
0047 
0048 #include <mpc55xx/emios.h>
0049 
0050 static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc)
0051 {
0052   return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CCNTR.R;
0053 }
0054 
0055 static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc)
0056 {
0057   return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.B.FLAG != 0;
0058 }
0059 
0060 static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc)
0061 {
0062   return rtems_timecounter_simple_upcounter_get(
0063     tc,
0064     mpc55xx_tc_get,
0065     mpc55xx_tc_is_pending
0066   );
0067 }
0068 
0069 static void mpc55xx_tc_at_tick(rtems_timecounter_simple *tc)
0070 {
0071   union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS;
0072   csr.B.FLAG = 1;
0073   EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.R = csr.R;
0074 }
0075 
0076 static void mpc55xx_tc_tick(rtems_timecounter_simple *tc)
0077 {
0078   rtems_timecounter_simple_upcounter_tick(
0079     tc,
0080     mpc55xx_tc_get,
0081     mpc55xx_tc_at_tick
0082   );
0083 }
0084 
0085 static void mpc55xx_clock_handler_install(rtems_interrupt_handler handler)
0086 {
0087   rtems_status_code sc = RTEMS_SUCCESSFUL;
0088 
0089   sc = mpc55xx_interrupt_handler_install(
0090     MPC55XX_IRQ_EMIOS(MPC55XX_CLOCK_EMIOS_CHANNEL),
0091     "clock",
0092     RTEMS_INTERRUPT_UNIQUE,
0093     MPC55XX_INTC_MIN_PRIORITY,
0094     handler,
0095     &mpc55xx_tc
0096   );
0097   if (sc != RTEMS_SUCCESSFUL) {
0098     bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_IRQ_INSTALL);
0099   }
0100 }
0101 
0102 static void mpc55xx_clock_initialize(void)
0103 {
0104   volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL];
0105   union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS;
0106   union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS;
0107   unsigned prescaler = mpc55xx_emios_global_prescaler();
0108   uint64_t reference_clock = bsp_clock_speed;
0109   uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
0110   uint64_t interval = (reference_clock * us_per_tick) / 1000000;
0111 
0112   /* Apply prescaler */
0113   if (prescaler > 0) {
0114     interval /= (uint64_t) prescaler;
0115   } else {
0116     bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_PRESCALER);
0117   }
0118 
0119   /* Check interval */
0120   if (interval == 0 || interval > MPC55XX_EMIOS_VALUE_MAX) {
0121     bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_INTERVAL);
0122   }
0123 
0124   /* Configure eMIOS channel */
0125 
0126   /* Set channel in GPIO mode */
0127   ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT;
0128   regs->CCR.R = ccr.R;
0129 
0130   /* Clear status flags */
0131   csr.B.OVR = 1;
0132   csr.B.OVFL = 1;
0133   csr.B.FLAG = 1;
0134   regs->CSR.R = csr.R;
0135 
0136   /* Set internal counter start value */
0137   regs->CCNTR.R = 1;
0138 
0139   /* Set timer period */
0140   regs->CADR.R = (uint32_t) interval - 1;
0141 
0142   /* Set control register */
0143   #if MPC55XX_CHIP_FAMILY == 551
0144     ccr.B.MODE = MPC55XX_EMIOS_MODE_MCB_UP_INT_CLK;
0145   #else
0146     ccr.B.MODE = MPC55XX_EMIOS_MODE_MC_UP_INT_CLK;
0147   #endif
0148   ccr.B.UCPREN = 1;
0149   ccr.B.FEN = 1;
0150   ccr.B.FREN = 1;
0151   regs->CCR.R = ccr.R;
0152 
0153   rtems_timecounter_simple_install(
0154     &mpc55xx_tc,
0155     reference_clock,
0156     interval,
0157     mpc55xx_tc_get_timecount
0158   );
0159 }
0160 
0161 #elif defined(MPC55XX_CLOCK_PIT_CHANNEL)
0162 
0163 static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc)
0164 {
0165   return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].CVAL.R;
0166 }
0167 
0168 static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc)
0169 {
0170   return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].TFLG.B.TIF != 0;
0171 }
0172 
0173 static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc)
0174 {
0175   return rtems_timecounter_simple_downcounter_get(
0176     tc,
0177     mpc55xx_tc_get,
0178     mpc55xx_tc_is_pending
0179   );
0180 }
0181 
0182 static void mpc55xx_tc_at_tick(rtems_timecounter_simple *tc)
0183 {
0184   volatile PIT_RTI_CHANNEL_tag *channel =
0185     &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL];
0186   PIT_RTI_TFLG_32B_tag tflg = { .B = { .TIF = 1 } };
0187 
0188   channel->TFLG.R = tflg.R;
0189 }
0190 
0191 static void mpc55xx_tc_tick(rtems_timecounter_simple *tc)
0192 {
0193   rtems_timecounter_simple_downcounter_tick(
0194     tc,
0195     mpc55xx_tc_get,
0196     mpc55xx_tc_at_tick
0197   );
0198 }
0199 
0200 static void mpc55xx_clock_handler_install(rtems_interrupt_handler handler)
0201 {
0202   rtems_status_code sc = RTEMS_SUCCESSFUL;
0203 
0204   sc = mpc55xx_interrupt_handler_install(
0205     MPC55XX_IRQ_PIT_CHANNEL(MPC55XX_CLOCK_PIT_CHANNEL),
0206     "clock",
0207     RTEMS_INTERRUPT_UNIQUE,
0208     MPC55XX_INTC_MIN_PRIORITY,
0209     handler,
0210     &mpc55xx_tc
0211   );
0212   if (sc != RTEMS_SUCCESSFUL) {
0213     bsp_fatal(MPC55XX_FATAL_CLOCK_PIT_IRQ_INSTALL);
0214   }
0215 }
0216 
0217 static void mpc55xx_clock_initialize(void)
0218 {
0219   volatile PIT_RTI_CHANNEL_tag *channel =
0220     &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL];
0221   uint64_t reference_clock = bsp_clock_speed;
0222   uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
0223   uint64_t interval = (reference_clock * us_per_tick) / 1000000;
0224   PIT_RTI_PITMCR_32B_tag pitmcr = { .B = { .FRZ = 1 } };
0225   PIT_RTI_TCTRL_32B_tag tctrl = { .B = { .TIE = 1, .TEN = 1 } };
0226 
0227   PIT_RTI.PITMCR.R = pitmcr.R;
0228   channel->LDVAL.R = interval;
0229   channel->TCTRL.R = tctrl.R;
0230 
0231   rtems_timecounter_simple_install(
0232     &mpc55xx_tc,
0233     reference_clock,
0234     interval,
0235     mpc55xx_tc_get_timecount
0236   );
0237 }
0238 
0239 #endif
0240 
0241 #define Clock_driver_timecounter_tick(arg) mpc55xx_tc_tick(arg)
0242 #define Clock_driver_support_initialize_hardware() \
0243   mpc55xx_clock_initialize()
0244 #define Clock_driver_support_install_isr(isr) \
0245   mpc55xx_clock_handler_install(isr)
0246 
0247 /* Include shared source clock driver code */
0248 #include "../../../shared/dev/clock/clockimpl.h"