diff options
Diffstat (limited to 'bsps/powerpc/mpc55xxevb')
-rw-r--r-- | bsps/powerpc/mpc55xxevb/clock/clock-config.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/bsps/powerpc/mpc55xxevb/clock/clock-config.c b/bsps/powerpc/mpc55xxevb/clock/clock-config.c new file mode 100644 index 0000000000..41320c842c --- /dev/null +++ b/bsps/powerpc/mpc55xxevb/clock/clock-config.c @@ -0,0 +1,257 @@ +/** + * @file + * + * @ingroup mpc55xx + * + * @brief Clock driver configuration. + */ + +/* + * Copyright (c) 2009-2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/fatal.h> +#include <bsp/irq.h> + +#include <mpc55xx/regs.h> + +#include <rtems/timecounter.h> + +void Clock_isr(void *arg); + +static rtems_timecounter_simple mpc55xx_tc; + +#if defined(MPC55XX_CLOCK_EMIOS_CHANNEL) + +#include <mpc55xx/emios.h> + +static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc) +{ + return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CCNTR.R; +} + +static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc) +{ + return EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.B.FLAG != 0; +} + +static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_upcounter_get( + tc, + mpc55xx_tc_get, + mpc55xx_tc_is_pending + ); +} + +static void mpc55xx_tc_at_tick(rtems_timecounter_simple *tc) +{ + union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; + csr.B.FLAG = 1; + EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.R = csr.R; +} + +static void mpc55xx_tc_tick(void) +{ + rtems_timecounter_simple_upcounter_tick( + &mpc55xx_tc, + mpc55xx_tc_get, + mpc55xx_tc_at_tick + ); +} + +static void mpc55xx_clock_handler_install(rtems_isr_entry isr) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = mpc55xx_interrupt_handler_install( + MPC55XX_IRQ_EMIOS(MPC55XX_CLOCK_EMIOS_CHANNEL), + "clock", + RTEMS_INTERRUPT_UNIQUE, + MPC55XX_INTC_MIN_PRIORITY, + (rtems_interrupt_handler) isr, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_IRQ_INSTALL); + } +} + +static void mpc55xx_clock_initialize(void) +{ + volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; + union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS; + union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; + unsigned prescaler = mpc55xx_emios_global_prescaler(); + uint64_t reference_clock = bsp_clock_speed; + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint64_t interval = (reference_clock * us_per_tick) / 1000000; + + /* Apply prescaler */ + if (prescaler > 0) { + interval /= (uint64_t) prescaler; + } else { + bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_PRESCALER); + } + + /* Check interval */ + if (interval == 0 || interval > MPC55XX_EMIOS_VALUE_MAX) { + bsp_fatal(MPC55XX_FATAL_CLOCK_EMIOS_INTERVAL); + } + + /* Configure eMIOS channel */ + + /* Set channel in GPIO mode */ + ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT; + regs->CCR.R = ccr.R; + + /* Clear status flags */ + csr.B.OVR = 1; + csr.B.OVFL = 1; + csr.B.FLAG = 1; + regs->CSR.R = csr.R; + + /* Set internal counter start value */ + regs->CCNTR.R = 1; + + /* Set timer period */ + regs->CADR.R = (uint32_t) interval - 1; + + /* Set control register */ + #if MPC55XX_CHIP_FAMILY == 551 + ccr.B.MODE = MPC55XX_EMIOS_MODE_MCB_UP_INT_CLK; + #else + ccr.B.MODE = MPC55XX_EMIOS_MODE_MC_UP_INT_CLK; + #endif + ccr.B.UCPREN = 1; + ccr.B.FEN = 1; + ccr.B.FREN = 1; + regs->CCR.R = ccr.R; + + rtems_timecounter_simple_install( + &mpc55xx_tc, + reference_clock, + interval, + mpc55xx_tc_get_timecount + ); +} + +static void mpc55xx_clock_cleanup(void) +{ + volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; + union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS; + + /* Set channel in GPIO mode */ + ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT; + regs->CCR.R = ccr.R; +} + +#elif defined(MPC55XX_CLOCK_PIT_CHANNEL) + +static uint32_t mpc55xx_tc_get(rtems_timecounter_simple *tc) +{ + return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].CVAL.R; +} + +static bool mpc55xx_tc_is_pending(rtems_timecounter_simple *tc) +{ + return PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL].TFLG.B.TIF != 0; +} + +static uint32_t mpc55xx_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + mpc55xx_tc_get, + mpc55xx_tc_is_pending + ); +} + +static void mpc55xx_tc_at_tick(rtems_timecounter_simple *tc) +{ + volatile PIT_RTI_CHANNEL_tag *channel = + &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL]; + PIT_RTI_TFLG_32B_tag tflg = { .B = { .TIF = 1 } }; + + channel->TFLG.R = tflg.R; +} + +static void mpc55xx_tc_tick(void) +{ + rtems_timecounter_simple_downcounter_tick( + &mpc55xx_tc, + mpc55xx_tc_get, + mpc55xx_tc_at_tick + ); +} + +static void mpc55xx_clock_handler_install(rtems_isr_entry isr) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = mpc55xx_interrupt_handler_install( + MPC55XX_IRQ_PIT_CHANNEL(MPC55XX_CLOCK_PIT_CHANNEL), + "clock", + RTEMS_INTERRUPT_UNIQUE, + MPC55XX_INTC_MIN_PRIORITY, + (rtems_interrupt_handler) isr, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(MPC55XX_FATAL_CLOCK_PIT_IRQ_INSTALL); + } +} + +static void mpc55xx_clock_initialize(void) +{ + volatile PIT_RTI_CHANNEL_tag *channel = + &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL]; + uint64_t reference_clock = bsp_clock_speed; + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint64_t interval = (reference_clock * us_per_tick) / 1000000; + PIT_RTI_PITMCR_32B_tag pitmcr = { .B = { .FRZ = 1 } }; + PIT_RTI_TCTRL_32B_tag tctrl = { .B = { .TIE = 1, .TEN = 1 } }; + + PIT_RTI.PITMCR.R = pitmcr.R; + channel->LDVAL.R = interval; + channel->TCTRL.R = tctrl.R; + + rtems_timecounter_simple_install( + &mpc55xx_tc, + reference_clock, + interval, + mpc55xx_tc_get_timecount + ); +} + +static void mpc55xx_clock_cleanup(void) +{ + volatile PIT_RTI_CHANNEL_tag *channel = + &PIT_RTI.CHANNEL [MPC55XX_CLOCK_PIT_CHANNEL]; + + channel->TCTRL.R = 0; +} + +#endif + +#define Clock_driver_timecounter_tick() mpc55xx_tc_tick() +#define Clock_driver_support_initialize_hardware() \ + mpc55xx_clock_initialize() +#define Clock_driver_support_install_isr(isr) \ + mpc55xx_clock_handler_install(isr) +#define Clock_driver_support_shutdown_hardware() \ + mpc55xx_clock_cleanup() + +/* Include shared source clock driver code */ +#include "../../../shared/dev/clock/clockimpl.h" |