forked from Imagelibrary/rtems
New (CVS import Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>'s
submission).
This commit is contained in:
474
c/src/lib/libbsp/powerpc/gen5200/clock/clock.c
Normal file
474
c/src/lib/libbsp/powerpc/gen5200/clock/clock.c
Normal file
@@ -0,0 +1,474 @@
|
||||
/*===============================================================*\
|
||||
| Project: RTEMS generic MPC5200 BSP |
|
||||
+-----------------------------------------------------------------+
|
||||
| File: clock.c
|
||||
+-----------------------------------------------------------------+
|
||||
| Partially based on the code references which are named below. |
|
||||
| Adaptions, modifications, enhancements and any recent parts of |
|
||||
| the code are: |
|
||||
| Copyright (c) 2005 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-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.com/license/LICENSE. |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
| this file contains the clock driver functions |
|
||||
+-----------------------------------------------------------------+
|
||||
| date history ID |
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
||||
| 01.12.05 creation doe |
|
||||
|*****************************************************************|
|
||||
|*CVS information: |
|
||||
|*(the following information is created automatically, |
|
||||
|*do not edit here) |
|
||||
|*****************************************************************|
|
||||
|* $Log$
|
||||
|* Revision 1.9 2005/12/09 08:57:03 thomas
|
||||
|* added/modifed file headers
|
||||
|*
|
||||
|* Revision 1.8 2005/12/06 14:30:42 thomas
|
||||
|* updated name for peripheral register block
|
||||
|*
|
||||
|* Revision 1.7 2005/12/06 14:11:11 thomas
|
||||
|* added EB file headers
|
||||
|*
|
||||
*
|
||||
|*****************************************************************|
|
||||
\*===============================================================*/
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* Module: clock.c */
|
||||
/* Date: 07/17/2003 */
|
||||
/* Purpose: RTEMS MPC5x00 clock driver */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Description: Use one of the GPTs for time base generation */
|
||||
/* instead of the decrementer. The routine initializes */
|
||||
/* the General Purpose Timer GPT6 on the MPC5x00. */
|
||||
/* The tick frequency is specified by the bsp. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Code */
|
||||
/* References: Clock driver for PPC403 */
|
||||
/* Module: clock.c */
|
||||
/* Project: RTEMS 4.6.0pre1 / PPC403 BSP */
|
||||
/* Version 1.16 */
|
||||
/* Date: 2002/11/01 */
|
||||
/* Author(s) / Copyright(s): */
|
||||
/* */
|
||||
/* Author: Jay Monkman (jmonkman@frasca.com) */
|
||||
/* Copyright (C) 1998 by Frasca International, Inc. */
|
||||
/* */
|
||||
/* Derived from c/src/lib/libcpu/ppc/ppc403/clock/clock.c: */
|
||||
/* */
|
||||
/* Author: Andrew Bray <andy@i-cubed.co.uk> */
|
||||
/* */
|
||||
/* COPYRIGHT (c) 1995 by i-cubed ltd. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/* Derived from c/src/lib/libcpu/hppa1.1/clock/clock.c: */
|
||||
/* */
|
||||
/* 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-1999. */
|
||||
/* 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.OARcorp.com/rtems/license.html. */
|
||||
/* */
|
||||
/* Modifications for PPC405GP by Dennis Ehlin */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Partially based on the code references which are named above. */
|
||||
/* Adaptions, modifications, enhancements and any recent parts of */
|
||||
/* the code are under the right of */
|
||||
/* */
|
||||
/* IPR Engineering, Dachauer Stra<72>e 38, D-80335 M<>nchen */
|
||||
/* Copyright(C) 2003 */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* IPR Engineering makes no representation or warranties with */
|
||||
/* respect to the performance of this computer program, and */
|
||||
/* specifically disclaims any responsibility for any damages, */
|
||||
/* special or consequential, connected with the use of this program. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version history: 1.0 */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/*#include "../include/bsp.h"*/
|
||||
#include "../include/bsp.h"
|
||||
#include <rtems/bspIo.h>
|
||||
/*#include "../irq/irq.h"*/
|
||||
#include "../irq/irq.h"
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/clockdrv.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
#include <stdlib.h> /* for atexit() */
|
||||
#include "../include/bsp.h"
|
||||
#include "../irq/irq.h"
|
||||
#include "../include/mpc5200.h"
|
||||
|
||||
volatile uint32_t Clock_driver_ticks;
|
||||
|
||||
void Clock_exit(void);
|
||||
|
||||
uint32_t counter_value;
|
||||
|
||||
volatile int ClockInitialized = 0;
|
||||
|
||||
|
||||
/*
|
||||
* These are set by clock driver during its init
|
||||
*/
|
||||
rtems_device_major_number rtems_clock_major = ~0;
|
||||
rtems_device_minor_number rtems_clock_minor;
|
||||
|
||||
|
||||
/*
|
||||
* ISR Handlers
|
||||
*/
|
||||
void mpc5200_gpt_clock_isr(rtems_irq_hdl_param handle)
|
||||
{
|
||||
uint32_t status;
|
||||
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)handle;
|
||||
|
||||
status = gpt->status;
|
||||
|
||||
|
||||
if(ClockInitialized && (status & GPT_STATUS_TEXP))
|
||||
{
|
||||
|
||||
gpt->status |= GPT_STATUS_TEXP;
|
||||
|
||||
|
||||
Clock_driver_ticks++;
|
||||
rtems_clock_tick();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize MPC5x00 GPT
|
||||
*/
|
||||
void mpc5200_init_gpt(uint32_t gpt_no)
|
||||
{
|
||||
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[gpt_no]);
|
||||
|
||||
gpt->status = GPT_STATUS_RESET;
|
||||
gpt->emsel = GPT_EMSEL_CE | GPT_EMSEL_ST_CONT | GPT_EMSEL_INTEN | GPT_EMSEL_GPIO_OUT_HIGH | GPT_EMSEL_TIMER_MS_GPIO;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set MPC5x00 GPT counter
|
||||
*/
|
||||
void mpc5200_set_gpt_count(uint32_t counter_value, uint32_t gpt_no)
|
||||
{
|
||||
uint32_t prescaler_value = 1;
|
||||
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[gpt_no]);
|
||||
|
||||
/* Calculate counter/prescaler value, e.g. IPB_Clock=33MHz -> Int. every 0,3 nsecs. - 130 secs.*/
|
||||
while((counter_value >= (1 << 16)) && (prescaler_value < (1 << 16)))
|
||||
{
|
||||
|
||||
prescaler_value++;
|
||||
counter_value /= prescaler_value;
|
||||
|
||||
}
|
||||
|
||||
counter_value = (uint16_t)counter_value;
|
||||
|
||||
gpt->count_in = (prescaler_value << 16) + counter_value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enable MPC5x00 GPT interrupt
|
||||
*/
|
||||
void mpc5200_enable_gpt_int(uint32_t gpt_no)
|
||||
{
|
||||
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[gpt_no]);
|
||||
|
||||
gpt->emsel |= GPT_EMSEL_CE | GPT_EMSEL_INTEN;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Disable MPC5x00 GPT interrupt
|
||||
*/
|
||||
void mpc5200_disable_gpt_int(uint32_t gpt_no)
|
||||
{
|
||||
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[gpt_no]);
|
||||
|
||||
gpt->emsel &= ~(GPT_EMSEL_CE | GPT_EMSEL_INTEN);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check MPC5x00 GPT status
|
||||
*/
|
||||
uint32_t mpc5200_check_gpt_status(uint32_t gpt_no)
|
||||
{
|
||||
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[gpt_no]);
|
||||
|
||||
return ((gpt->emsel) & (GPT_EMSEL_CE | GPT_EMSEL_INTEN));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void clockOn(const rtems_irq_connect_data* irq)
|
||||
{
|
||||
uint32_t gpt_no;
|
||||
|
||||
|
||||
gpt_no = BSP_SIU_IRQ_TMR0 - (irq->name);
|
||||
|
||||
counter_value = rtems_configuration_get_microseconds_per_tick() *
|
||||
rtems_cpu_configuration_get_clicks_per_usec();
|
||||
|
||||
mpc5200_set_gpt_count(counter_value, (uint32_t)gpt_no);
|
||||
mpc5200_enable_gpt_int((uint32_t)gpt_no);
|
||||
|
||||
Clock_driver_ticks = 0;
|
||||
ClockInitialized = 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void clockOff(const rtems_irq_connect_data* irq)
|
||||
{
|
||||
uint32_t gpt_no;
|
||||
|
||||
gpt_no = BSP_SIU_IRQ_TMR0 - (irq->name);
|
||||
|
||||
mpc5200_disable_gpt_int((uint32_t)gpt_no);
|
||||
|
||||
ClockInitialized = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int clockIsOn(const rtems_irq_connect_data* irq)
|
||||
{
|
||||
uint32_t gpt_no;
|
||||
|
||||
gpt_no = BSP_SIU_IRQ_TMR0 - (irq->name);
|
||||
|
||||
if(mpc5200_check_gpt_status(gpt_no) && ClockInitialized)
|
||||
return ClockInitialized;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int BSP_get_clock_irq_level()
|
||||
{
|
||||
|
||||
/*
|
||||
* Caution : if you change this, you must change the
|
||||
* definition of BSP_PERIODIC_TIMER accordingly
|
||||
*/
|
||||
return BSP_PERIODIC_TIMER;
|
||||
}
|
||||
|
||||
|
||||
int BSP_disconnect_clock_handler (void)
|
||||
{
|
||||
rtems_irq_connect_data clockIrqData;
|
||||
clockIrqData.name = BSP_PERIODIC_TIMER;
|
||||
|
||||
|
||||
if (!BSP_get_current_rtems_irq_handler(&clockIrqData))
|
||||
{
|
||||
|
||||
printk("Unable to stop system clock\n");
|
||||
rtems_fatal_error_occurred(1);
|
||||
|
||||
}
|
||||
|
||||
return BSP_remove_rtems_irq_handler (&clockIrqData);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int BSP_connect_clock_handler (uint32_t gpt_no)
|
||||
{
|
||||
|
||||
rtems_irq_hdl hdl = 0;
|
||||
rtems_irq_connect_data clockIrqData;
|
||||
|
||||
|
||||
/*
|
||||
* Reinit structure
|
||||
*/
|
||||
|
||||
clockIrqData.name = BSP_PERIODIC_TIMER;
|
||||
|
||||
if(!BSP_get_current_rtems_irq_handler(&clockIrqData))
|
||||
{
|
||||
|
||||
printk("Unable to get system clock handler\n");
|
||||
rtems_fatal_error_occurred(1);
|
||||
|
||||
}
|
||||
|
||||
if(!BSP_remove_rtems_irq_handler (&clockIrqData))
|
||||
{
|
||||
|
||||
printk("Unable to remove current system clock handler\n");
|
||||
rtems_fatal_error_occurred(1);
|
||||
|
||||
}
|
||||
|
||||
if ((gpt_no >= GPT0) ||
|
||||
(gpt_no <= GPT7)) {
|
||||
hdl = (rtems_irq_hdl_param )&mpc5200.gpt[gpt_no];
|
||||
}
|
||||
else {
|
||||
printk("Unable to set system clock handler\n");
|
||||
rtems_fatal_error_occurred(1);
|
||||
}
|
||||
|
||||
clockIrqData.hdl = mpc5200_gpt_clock_isr;
|
||||
clockIrqData.handle = (rtems_irq_hdl_param) hdl;
|
||||
clockIrqData.on = clockOn;
|
||||
clockIrqData.off = clockOff;
|
||||
clockIrqData.isOn = clockIsOn;
|
||||
|
||||
return BSP_install_rtems_irq_handler (&clockIrqData);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called via atexit()
|
||||
* Remove the clock interrupt handler by setting handler to NULL
|
||||
*/
|
||||
void Clock_exit(void)
|
||||
{
|
||||
|
||||
(void) BSP_disconnect_clock_handler ();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Install_clock(rtems_device_minor_number gpt_no)
|
||||
{
|
||||
|
||||
Clock_driver_ticks = 0;
|
||||
|
||||
counter_value = rtems_configuration_get_microseconds_per_tick() *
|
||||
rtems_cpu_configuration_get_clicks_per_usec();
|
||||
|
||||
mpc5200_init_gpt((uint32_t)gpt_no);
|
||||
mpc5200_set_gpt_count(counter_value, (uint32_t)gpt_no);
|
||||
|
||||
|
||||
BSP_connect_clock_handler(gpt_no);
|
||||
|
||||
ClockInitialized = 1;
|
||||
|
||||
atexit(Clock_exit);
|
||||
|
||||
}
|
||||
|
||||
void ReInstall_clock(uint32_t gpt_no)
|
||||
{
|
||||
|
||||
BSP_connect_clock_handler(gpt_no);
|
||||
|
||||
}
|
||||
|
||||
|
||||
rtems_device_driver Clock_initialize
|
||||
(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *pargp
|
||||
)
|
||||
{
|
||||
/* force minor according to definitions in irq.h */
|
||||
minor = BSP_PERIODIC_TIMER - BSP_SIU_IRQ_TMR0;
|
||||
|
||||
Install_clock((uint32_t)minor);
|
||||
|
||||
/*
|
||||
* make major/minor avail to others such as shared memory driver
|
||||
*/
|
||||
rtems_clock_major = major;
|
||||
rtems_clock_minor = minor;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
|
||||
}
|
||||
|
||||
rtems_device_driver Clock_control
|
||||
(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *pargp
|
||||
) {
|
||||
|
||||
rtems_libio_ioctl_args_t *args = pargp;
|
||||
|
||||
/* forec minor according to definitions in irq.h */
|
||||
minor = BSP_PERIODIC_TIMER - BSP_SIU_IRQ_TMR0;
|
||||
|
||||
if(args != 0) {
|
||||
/*
|
||||
* This is hokey, but until we get a defined interface
|
||||
* to do this, it will just be this simple...
|
||||
*/
|
||||
if(args->command == rtems_build_name('I', 'S', 'R', ' ')) {
|
||||
if ((minor >= GPT0) ||
|
||||
(minor <= GPT7)) {
|
||||
mpc5200_gpt_clock_isr((rtems_irq_hdl_param )&mpc5200.gpt[minor]);
|
||||
}
|
||||
else {
|
||||
printk("Unable to call system clock handler\n");
|
||||
rtems_fatal_error_occurred(1);
|
||||
}
|
||||
}
|
||||
else if(args->command == rtems_build_name('N', 'E', 'W', ' ')) {
|
||||
ReInstall_clock((uint32_t)minor);
|
||||
}
|
||||
}
|
||||
return RTEMS_SUCCESSFUL;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user