summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/mpc55xxevb/clock/clock-config.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/mpc55xxevb/clock/clock-config.c')
-rw-r--r--bsps/powerpc/mpc55xxevb/clock/clock-config.c257
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"