summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/shared/clock
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-19 06:35:52 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 09:57:01 +0200
commit7632906fc290b652416ab59eb5fb49356c064ed6 (patch)
treeac036b1f95637e044e10138ceea8d2b56d80ec97 /bsps/powerpc/shared/clock
parentbsps: Move bspsmpgetcurrentprocessor.c to bsps (diff)
downloadrtems-7632906fc290b652416ab59eb5fb49356c064ed6.tar.bz2
bsps: Move clock drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/powerpc/shared/clock')
-rw-r--r--bsps/powerpc/shared/clock/clock-ppc-dec.c266
-rw-r--r--bsps/powerpc/shared/clock/clock-ppc403.c275
-rw-r--r--bsps/powerpc/shared/clock/clock.c247
-rw-r--r--bsps/powerpc/shared/clock/p_clock.c43
4 files changed, 831 insertions, 0 deletions
diff --git a/bsps/powerpc/shared/clock/clock-ppc-dec.c b/bsps/powerpc/shared/clock/clock-ppc-dec.c
new file mode 100644
index 0000000000..c9bb16c451
--- /dev/null
+++ b/bsps/powerpc/shared/clock/clock-ppc-dec.c
@@ -0,0 +1,266 @@
+/**
+ * @brief Clock Tick Device Driver
+ *
+ * This routine utilizes the Decrementer Register common to the PPC family.
+ *
+ * The tick frequency is directly programmed to the configured number of
+ * microseconds per tick.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2014.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may in
+ * the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modified to support the MPC750.
+ * Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/clockdrv.h>
+#include <stdlib.h> /* for atexit() */
+#include <assert.h>
+#include <libcpu/c_clock.h>
+#include <libcpu/cpuIdent.h>
+#include <libcpu/spr.h>
+#include <rtems/bspIo.h> /* for printk() */
+#include <libcpu/powerpc-utility.h>
+#include <rtems/timecounter.h>
+#include <rtems/score/percpu.h>
+
+#include <bspopts.h> /* for CLOCK_DRIVER_USE_FAST_IDLE */
+
+SPR_RW(BOOKE_TCR)
+SPR_RW(BOOKE_TSR)
+SPR_RW(BOOKE_DECAR)
+
+extern int BSP_connect_clock_handler (void);
+
+/*
+ * Clock ticks since initialization
+ */
+volatile uint32_t Clock_driver_ticks;
+
+/*
+ * This is the value programmed into the count down timer.
+ */
+static uint32_t Clock_Decrementer_value;
+
+static struct timecounter Clock_TC;
+
+static uint32_t Clock_Get_timecount(struct timecounter *tc)
+{
+ return ppc_time_base();
+}
+
+void clockOff(void* unused)
+{
+ rtems_interrupt_level l;
+
+ if ( ppc_cpu_is_bookE() ) {
+ rtems_interrupt_disable(l);
+ _write_BOOKE_TCR(_read_BOOKE_TCR() & ~BOOKE_TCR_DIE);
+ rtems_interrupt_enable(l);
+ } else {
+ /*
+ * Nothing to do as we cannot disable all interrupts and
+ * the decrementer interrupt enable is MSR_EE
+ */
+ }
+}
+
+void clockOn(void* unused)
+{
+ rtems_interrupt_level l;
+
+ PPC_Set_decrementer( Clock_Decrementer_value );
+
+ if ( ppc_cpu_is_bookE() ) {
+ _write_BOOKE_DECAR( Clock_Decrementer_value );
+
+ rtems_interrupt_disable(l);
+
+ /* clear pending/stale irq */
+ _write_BOOKE_TSR( BOOKE_TSR_DIS );
+ /* enable */
+ _write_BOOKE_TCR( _read_BOOKE_TCR() | BOOKE_TCR_DIE );
+
+ rtems_interrupt_enable(l);
+
+ }
+}
+
+static void clockHandler(void)
+{
+ #if (CLOCK_DRIVER_USE_FAST_IDLE == 1)
+ rtems_interrupt_level level;
+ uint32_t tb;
+
+ rtems_interrupt_disable(level);
+
+ tb = ppc_time_base();
+ rtems_timecounter_tick();
+
+ while ( _Thread_Heir == _Thread_Executing && _Thread_Executing->is_idle ) {
+ tb += Clock_Decrementer_value;
+ ppc_set_time_base( tb );
+ rtems_timecounter_tick();
+ }
+
+ rtems_interrupt_enable(level);
+ #else
+ rtems_timecounter_tick();
+ #endif
+}
+
+static void (*clock_handler)(void);
+
+/*
+ * Clock_isr
+ *
+ * This is the clock tick interrupt handler.
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ *
+ */
+void clockIsr(void *unused)
+{
+ int decr;
+
+ /*
+ * The driver has seen another tick.
+ */
+ do {
+ register uint32_t flags;
+
+ rtems_interrupt_disable(flags);
+ __asm__ volatile (
+ "mfdec %0; add %0, %0, %1; mtdec %0"
+ : "=&r"(decr)
+ : "r"(Clock_Decrementer_value)
+ );
+ rtems_interrupt_enable(flags);
+
+ Clock_driver_ticks += 1;
+ /*
+ * Real Time Clock counter/timer is set to automatically reload.
+ */
+ clock_handler();
+ } while ( decr < 0 );
+}
+
+/*
+ * Clock_isr_bookE
+ *
+ * This is the clock tick interrupt handler
+ * for bookE CPUs. For efficiency reasons we
+ * provide a separate handler rather than
+ * checking the CPU type each time.
+ */
+void clockIsrBookE(void *unused)
+{
+ /* Note: TSR bit has already been cleared in the exception handler */
+
+ /*
+ * The driver has seen another tick.
+ */
+
+ Clock_driver_ticks += 1;
+
+ /*
+ * Real Time Clock counter/timer is set to automatically reload.
+ */
+ clock_handler();
+}
+
+int clockIsOn(void* unused)
+{
+ uint32_t msr_value;
+
+ _CPU_MSR_GET( msr_value );
+
+ if ( ppc_cpu_is_bookE() && ! (_read_BOOKE_TCR() & BOOKE_TCR_DIE) )
+ msr_value = 0;
+
+ if (msr_value & MSR_EE) return 1;
+
+ return 0;
+}
+
+/*
+ * Clock_exit
+ *
+ * This routine allows the clock driver to exit by masking the interrupt and
+ * disabling the clock's counter.
+ */
+void Clock_exit( void )
+{
+ (void) BSP_disconnect_clock_handler ();
+}
+
+/*
+ * Clock_initialize
+ *
+ * This routine initializes the clock driver.
+ */
+rtems_device_driver Clock_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *pargp
+)
+{
+ rtems_interrupt_level l,tcr;
+
+ Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
+ rtems_configuration_get_milliseconds_per_tick();
+
+ /* set the decrementer now, prior to installing the handler
+ * so no interrupts will happen in a while.
+ */
+ PPC_Set_decrementer( (unsigned)-1 );
+
+ /* On a bookE CPU the decrementer works differently. It doesn't
+ * count past zero but we can enable auto-reload :-)
+ */
+ if ( ppc_cpu_is_bookE() ) {
+
+ rtems_interrupt_disable(l);
+
+ tcr = _read_BOOKE_TCR();
+ tcr |= BOOKE_TCR_ARE;
+ tcr &= ~BOOKE_TCR_DIE;
+ _write_BOOKE_TCR(tcr);
+
+ rtems_interrupt_enable(l);
+ }
+
+ Clock_TC.tc_get_timecount = Clock_Get_timecount;
+ Clock_TC.tc_counter_mask = 0xffffffff;
+ Clock_TC.tc_frequency = (UINT64_C(1000) * BSP_bus_frequency) / BSP_time_base_divisor;
+ Clock_TC.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+ rtems_timecounter_install(&Clock_TC);
+
+ /*
+ * If a decrementer exception was pending, it is cleared by
+ * executing the default (nop) handler at this point;
+ * The next exception will then be taken by our clock handler.
+ * Clock handler installation initializes the decrementer to
+ * the correct value.
+ */
+ clock_handler = clockHandler;
+ if (!BSP_connect_clock_handler ()) {
+ printk("Unable to initialize system clock\n");
+ rtems_fatal_error_occurred(1);
+ }
+
+ return RTEMS_SUCCESSFUL;
+} /* Clock_initialize */
diff --git a/bsps/powerpc/shared/clock/clock-ppc403.c b/bsps/powerpc/shared/clock/clock-ppc403.c
new file mode 100644
index 0000000000..64e6f29d39
--- /dev/null
+++ b/bsps/powerpc/shared/clock/clock-ppc403.c
@@ -0,0 +1,275 @@
+/**
+ * @file
+ *
+ * This routine initializes the interval timer on the
+ * PowerPC 403 CPU. The tick frequency is specified by the BSP.
+ */
+
+/*
+ * Original PPC403 Code from:
+ * Author: Andrew Bray <andy@i-cubed.co.uk>
+ * COPYRIGHT (c) 1995 by i-cubed ltd.
+ *
+ * Modifications for PPC405GP by Dennis Ehlin
+ *
+ * To anyone who acknowledges that this file is provided "AS IS"
+ * without any express or implied warranty:
+ * permission to use, copy, modify, and distribute this file
+ * for any purpose is hereby granted without fee, provided that
+ * the above copyright notice and this notice appears in all
+ * copies, and that the name of i-cubed limited not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * i-cubed limited makes no representations about the suitability
+ * of this software for any purpose.
+ *
+ * Modifications for deriving timer clock from cpu system clock by
+ * Thomas Doerfler <td@imd.m.isar.de>
+ * for these modifications:
+ * COPYRIGHT (c) 1997 by IMD, Puchheim, Germany.
+ *
+ * COPYRIGHT (c) 1989-2012.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * 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 <rtems.h>
+#include <rtems/clockdrv.h>
+#include <rtems/libio.h>
+#include <stdlib.h> /* for atexit() */
+#include <rtems/bspIo.h>
+#include <rtems/powerpc/powerpc.h>
+
+/*
+ * check, which exception handling code is present
+ */
+
+#include <bsp.h>
+
+#include <bsp/vectors.h>
+#include <bsp/irq.h>
+
+extern uint32_t bsp_clicks_per_usec;
+
+volatile uint32_t Clock_driver_ticks;
+static uint32_t pit_value, tick_time;
+static bool auto_restart;
+
+void Clock_exit( void );
+
+static inline uint32_t get_itimer(void)
+{
+ register uint32_t rc;
+
+#ifndef ppc405 /* this is a ppc403 */
+ __asm__ volatile ("mfspr %0, 0x3dd" : "=r" ((rc))); /* TBLO */
+#else /* ppc405 */
+ __asm__ volatile ("mfspr %0, 0x10c" : "=r" ((rc))); /* 405GP TBL */
+#endif /* ppc405 */
+
+ return rc;
+}
+
+/*
+ * ISR Handler
+ */
+static void Clock_isr(void* handle)
+{
+ uint32_t clicks_til_next_interrupt;
+#if defined(BSP_PPC403_CLOCK_ISR_IRQ_LEVEL)
+ uint32_t l_orig = _ISR_Get_level();
+#endif
+
+ if (!auto_restart) {
+ uint32_t itimer_value;
+ /*
+ * setup for next interrupt; making sure the new value is reasonably
+ * in the future.... in case we lost out on an interrupt somehow
+ */
+ itimer_value = get_itimer();
+ tick_time += pit_value;
+
+ /*
+ * how far away is next interrupt *really*
+ * It may be a long time; this subtraction works even if
+ * Clock_clicks_interrupt < Clock_clicks_low_order via
+ * the miracle of unsigned math.
+ */
+ clicks_til_next_interrupt = tick_time - itimer_value;
+
+ /*
+ * If it is too soon then bump it up.
+ * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
+ * But setting it low is useful for debug, so...
+ */
+ if (clicks_til_next_interrupt < 400) {
+ tick_time = itimer_value + 1000;
+ clicks_til_next_interrupt = 1000;
+ /* XXX: count these! this should be rare */
+ }
+
+ /*
+ * If it is too late, that means we missed the interrupt somehow.
+ * Rather than wait 35-50s for a wrap, we just fudge it here.
+ */
+ if (clicks_til_next_interrupt > pit_value) {
+ tick_time = itimer_value + 1000;
+ clicks_til_next_interrupt = 1000;
+ /* XXX: count these! this should never happen :-) */
+ }
+
+ __asm__ volatile ("mtspr 0x3db, %0" :: "r"
+ (clicks_til_next_interrupt)); /* PIT */
+ }
+
+ __asm__ volatile ("mtspr 0x3d8, %0" :: "r" (0x08000000)); /* TSR */
+
+ Clock_driver_ticks++;
+
+ /* Give BSP a chance to say if they want to re-enable interrupts */
+#if defined(BSP_PPC403_CLOCK_ISR_IRQ_LEVEL)
+ _ISR_Set_level(BSP_PPC403_CLOCK_ISR_IRQ_LEVEL);
+#endif
+ rtems_clock_tick();
+
+#if defined(BSP_PPC403_CLOCK_ISR_IRQ_LEVEL)
+ _ISR_Set_level(l_orig)
+#endif
+}
+
+static int ClockIsOn(const rtems_irq_connect_data* unused)
+{
+ register uint32_t tcr;
+
+ __asm__ volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
+
+ return (tcr & 0x04000000) != 0;
+}
+
+static void ClockOff(const rtems_irq_connect_data* unused)
+{
+ register uint32_t tcr;
+
+ __asm__ volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
+ tcr &= ~ 0x04400000;
+ __asm__ volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
+}
+
+static void ClockOn(const rtems_irq_connect_data* unused)
+{
+ uint32_t iocr;
+ register uint32_t tcr;
+#ifndef ppc405
+ uint32_t pvr;
+#endif /* ppc403 */
+
+ Clock_driver_ticks = 0;
+
+#ifndef ppc405 /* this is a ppc403 */
+ __asm__ volatile ("mfdcr %0, 0xa0" : "=r" (iocr)); /* IOCR */
+ iocr &= ~4; /* timer clocked from system clock */
+ __asm__ volatile ("mtdcr 0xa0, %0" : "=r" (iocr) : "0" (iocr)); /* IOCR */
+
+ __asm__ volatile ("mfspr %0, 0x11f" : "=r" ((pvr))); /* PVR */
+ if (((pvr & 0xffff0000) >> 16) != 0x0020)
+ return; /* Not a ppc403 */
+
+ if ((pvr & 0xff00) == 0x0000) /* 403GA */
+#if 0 /* FIXME: in which processor versions will "autoload" work properly? */
+ auto_restart = (pvr & 0x00f0) > 0x0000 ? true : false;
+#else
+ /* no known chip version supports auto restart of timer... */
+ auto_restart = false;
+#endif
+ else if ((pvr & 0xff00) == 0x0100) /* 403GB */
+ auto_restart = true;
+
+#else /* ppc405 */
+ __asm__ volatile ("mfdcr %0, 0x0b2" : "=r" (iocr)); /*405GP CPC0_CR1 */
+ iocr &=~0x800000; /* timer clocked from system clock CETE*/
+ __asm__ volatile ("mtdcr 0x0b2, %0" : "=r" (iocr) : "0" (iocr)); /* 405GP CPC0_CR1 */
+
+ /*
+ * Enable auto restart
+ */
+ auto_restart = true;
+#endif /* ppc405 */
+
+ pit_value = rtems_configuration_get_microseconds_per_tick() *
+ bsp_clicks_per_usec;
+
+ /*
+ * Set PIT value
+ */
+ __asm__ volatile ("mtspr 0x3db, %0" : : "r" (pit_value)); /* PIT */
+
+ /*
+ * Set timer to autoreload, bit TCR->ARE = 1 0x0400000
+ * Enable PIT interrupt, bit TCR->PIE = 1 0x4000000
+ */
+ tick_time = get_itimer() + pit_value;
+
+ __asm__ volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
+ tcr = (tcr & ~0x04400000) | (auto_restart ? 0x04400000 : 0x04000000);
+#if 1
+ __asm__ volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
+#endif
+}
+
+static void Install_clock(void (*clock_isr)(void *))
+{
+ rtems_irq_connect_data clockIrqConnData;
+
+ Clock_driver_ticks = 0;
+
+ /*
+ * initialize the interval here
+ * First tick is set to right amount of time in the future
+ * Future ticks will be incremented over last value set
+ * in order to provide consistent clicks in the face of
+ * interrupt overhead
+ */
+ clockIrqConnData.on = ClockOn;
+ clockIrqConnData.off = ClockOff;
+ clockIrqConnData.isOn = ClockIsOn;
+ clockIrqConnData.name = BSP_PIT;
+ clockIrqConnData.hdl = clock_isr;
+ if (!BSP_install_rtems_irq_handler (&clockIrqConnData)) {
+ printk("Unable to connect Clock Irq handler\n");
+ rtems_fatal_error_occurred(1);
+ }
+
+ atexit(Clock_exit);
+}
+
+/*
+ * Called via atexit()
+ * Remove the clock interrupt handler by setting handler to NULL
+ *
+ * This will not work on the 405GP because
+ * when bit's are set in TCR they can only be unset by a reset
+ */
+void Clock_exit(void)
+{
+ rtems_irq_connect_data clockIrqConnData;
+
+ clockIrqConnData.name = BSP_PIT;
+ if (!BSP_get_current_rtems_irq_handler(&clockIrqConnData)) {
+ printk("Unable to stop system clock\n");
+ rtems_fatal_error_occurred(1);
+ }
+
+ BSP_remove_rtems_irq_handler (&clockIrqConnData);
+}
+
+rtems_device_driver Clock_initialize(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *pargp)
+{
+ Install_clock( Clock_isr );
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/powerpc/shared/clock/clock.c b/bsps/powerpc/shared/clock/clock.c
new file mode 100644
index 0000000000..431488a901
--- /dev/null
+++ b/bsps/powerpc/shared/clock/clock.c
@@ -0,0 +1,247 @@
+/**
+ * @file
+ *
+ * @ingroup powerpc_shared
+ *
+ * @brief Source file for a clock driver.
+ */
+
+/*
+ * Copyright (c) 2008-2015 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 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 <rtems.h>
+#include <rtems/clockdrv.h>
+#include <rtems/timecounter.h>
+
+#include <libcpu/powerpc-utility.h>
+#include <bsp/vectors.h>
+
+#define RTEMS_STATUS_CHECKS_USE_PRINTK
+
+#include <rtems/status-checks.h>
+
+/*
+ * This variable must be defined in the BSP and valid before clock driver
+ * initialization.
+ */
+extern uint32_t bsp_time_base_frequency;
+
+#define PPC405_PIT 0x3db
+
+#define PPC_CLOCK_DECREMENTER_MAX UINT32_MAX
+
+volatile uint32_t Clock_driver_ticks = 0;
+
+static uint32_t ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
+
+static uint32_t ppc_clock_next_time_base;
+
+static struct timecounter ppc_tc;
+
+static uint32_t ppc_get_timecount(struct timecounter *tc)
+{
+ return ppc_time_base();
+}
+
+static void ppc_clock_no_tick(void)
+{
+ /* Do nothing */
+}
+
+static void (*ppc_clock_tick)(void) = ppc_clock_no_tick;
+
+static int ppc_clock_exception_handler(
+ BSP_Exception_frame *frame,
+ unsigned number
+)
+{
+ uint32_t delta = ppc_clock_decrementer_value;
+ uint32_t next = ppc_clock_next_time_base;
+ uint32_t dec = 0;
+ uint32_t now = 0;
+ uint32_t msr = 0;
+
+ do {
+ /* Increment clock ticks */
+ Clock_driver_ticks += 1;
+
+ /* Enable external exceptions */
+ msr = ppc_external_exceptions_enable();
+
+ /* Call clock ticker */
+ ppc_clock_tick();
+
+ /* Restore machine state */
+ ppc_external_exceptions_disable( msr);
+
+ /* Next time base */
+ next += delta;
+
+ /* Current time */
+ now = ppc_time_base();
+
+ /* New decrementer value */
+ dec = next - now;
+ } while (dec > delta);
+
+ /* Set decrementer */
+ ppc_set_decrementer_register( dec);
+
+ /* Expected next time base */
+ ppc_clock_next_time_base = next;
+
+ return 0;
+}
+
+static int ppc_clock_exception_handler_first(
+ BSP_Exception_frame *frame,
+ unsigned number
+)
+{
+ /* We have to clear the first pending decrementer exception this way */
+
+ if (ppc_decrementer_register() >= 0x80000000) {
+ ppc_clock_exception_handler( frame, number);
+ }
+
+ ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler);
+
+ return 0;
+}
+
+static int ppc_clock_exception_handler_booke(
+ BSP_Exception_frame *frame,
+ unsigned number
+)
+{
+ uint32_t msr;
+
+ /* Acknowledge decrementer request */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_TSR, BOOKE_TSR_DIS);
+
+ /* Increment clock ticks */
+ Clock_driver_ticks += 1;
+
+ /* Enable external exceptions */
+ msr = ppc_external_exceptions_enable();
+
+ /* Call clock ticker */
+ ppc_clock_tick();
+
+ /* Restore machine state */
+ ppc_external_exceptions_disable( msr);
+
+ return 0;
+}
+
+static int ppc_clock_exception_handler_ppc405(BSP_Exception_frame *frame, unsigned number)
+{
+ uint32_t msr;
+
+ /* Acknowledge PIT request */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_TSR, BOOKE_TSR_DIS);
+
+ /* Increment clock ticks */
+ Clock_driver_ticks += 1;
+
+ /* Enable external exceptions */
+ msr = ppc_external_exceptions_enable();
+
+ /* Call clock ticker */
+ ppc_clock_tick();
+
+ /* Restore machine state */
+ ppc_external_exceptions_disable(msr);
+
+ return 0;
+}
+
+void Clock_exit(void)
+{
+ /* Set the decrementer to the maximum value */
+ ppc_set_decrementer_register( PPC_CLOCK_DECREMENTER_MAX);
+
+ /* Use default clock handler */
+ ppc_clock_tick = ppc_clock_no_tick;
+}
+
+rtems_device_driver Clock_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ uint64_t frequency = bsp_time_base_frequency;
+ uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
+ uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
+
+ /*
+ * Set default ticker.
+ */
+ ppc_clock_tick = rtems_timecounter_tick;
+
+ if (ppc_cpu_is_bookE() != PPC_BOOKE_405) {
+ /* Decrementer value */
+ ppc_clock_decrementer_value = interval - 1;
+
+ /* Check decrementer value */
+ if (ppc_clock_decrementer_value == 0) {
+ ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
+ RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n");
+ }
+ if (ppc_cpu_is_bookE()) {
+ /* Set decrementer auto-reload value */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);
+
+ /* Install exception handler */
+ ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);
+
+ /* Enable decrementer and auto-reload */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
+ } else {
+ /* Here the decrementer value is actually the interval */
+ ++ppc_clock_decrementer_value;
+
+ /* Initialize next time base */
+ ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;
+
+ /* Install exception handler */
+ ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
+ }
+
+ /* Set the decrementer value */
+ ppc_set_decrementer_register( ppc_clock_decrementer_value);
+ } else {
+ /* PIT interval value */
+ ppc_clock_decrementer_value = interval;
+
+ /* Install exception handler */
+ ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405);
+
+ /* Enable PIT and auto-reload */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(PPC405_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
+
+ /* Set PIT auto-reload and initial value */
+ PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval);
+ }
+
+ /* Install timecounter */
+ ppc_tc.tc_get_timecount = ppc_get_timecount;
+ ppc_tc.tc_counter_mask = 0xffffffff;
+ ppc_tc.tc_frequency = frequency;
+ ppc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+ rtems_timecounter_install(&ppc_tc);
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/powerpc/shared/clock/p_clock.c b/bsps/powerpc/shared/clock/p_clock.c
new file mode 100644
index 0000000000..1ff7ca06a6
--- /dev/null
+++ b/bsps/powerpc/shared/clock/p_clock.c
@@ -0,0 +1,43 @@
+/*
+ * Clock Tick interrupt conexion code.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-1997.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may in
+ * the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modified to support the MPC750.
+ * Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
+ */
+
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <libcpu/c_clock.h>
+#include <libcpu/cpuIdent.h>
+
+static rtems_irq_connect_data clockIrqData;
+static rtems_irq_connect_data clockIrqData = {
+ BSP_DECREMENTER,
+ clockIsr,
+ NULL,
+ (rtems_irq_enable)clockOn,
+ (rtems_irq_disable)clockOff,
+ (rtems_irq_is_enabled) clockIsOn
+};
+
+int BSP_disconnect_clock_handler(void)
+{
+ return BSP_remove_rtems_irq_handler(&clockIrqData);
+}
+
+int BSP_connect_clock_handler(void)
+{
+ if ( ppc_cpu_is_bookE() )
+ clockIrqData.hdl = clockIsrBookE;
+
+ return BSP_install_rtems_irq_handler(&clockIrqData);
+}