summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c
blob: 0d1561880f1e343b84bab78ae5dca19ab6008f56 (plain) (tree)
































                                                          









                                                           


                                                               
                                                                    



                                          
                                                    


                              
                                  

        
                 











                                                                               

                                                                 













                                                               
 


                                             
 




                          
 


                                        

                                         
 
                            
                                 
                                                 

                                                
      

















                                                                               
                                                    







                                                                







                                                                               
 
                                    
 
 


                                                                             
                                             

                                                                        
 




                                                     
/**
 * @file
 *
 * @ingroup mpc55xx
 *
 * @brief Clock driver configuration.
 */

/*
 * Copyright (c) 2009
 * 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.
 */

#include <mpc55xx/regs.h>
#include <mpc55xx/emios.h>

#include <rtems.h>

#include <bsp.h>
#include <bsp/irq.h>

#define RTEMS_STATUS_CHECKS_USE_PRINTK

#include <rtems/status-checks.h>

/* This is defined in clockdrv_shell.h */
rtems_isr Clock_isr( rtems_vector_number vector);

#define Clock_driver_support_at_tick() \
 do { \
    union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; \
    csr.B.FLAG = 1; \
    EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.R = csr.R; \
 } while (0)

static uint64_t mpc55xx_clock_factor;

static void mpc55xx_clock_handler_install( rtems_isr_entry isr,
					   rtems_isr_entry *old_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
  );
 *old_isr = NULL;
  RTEMS_CHECK_SC_VOID( sc, "install clock interrupt handler");
}

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 interval = ((uint64_t) bsp_clock_speed
    * (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000;

  mpc55xx_clock_factor = (1000000000ULL << 32) / bsp_clock_speed;

  /* Apply prescaler */
  if (prescaler > 0) {
    interval /= (uint64_t) prescaler;
  } else {
    RTEMS_SYSLOG_ERROR( "unexpected global eMIOS prescaler\n");
  }

  /* Check interval */
  if (interval == 0 || interval > MPC55XX_EMIOS_VALUE_MAX) {
    interval = MPC55XX_EMIOS_VALUE_MAX;
    RTEMS_SYSLOG_ERROR( "clock timer interval out of range\n");
  }

  /* 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_TYPE / 10 == 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;
}

static void mpc55xx_clock_cleanup( void)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  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;

  /* Remove interrupt handler */
  sc = rtems_interrupt_handler_remove(
    MPC55XX_IRQ_EMIOS( MPC55XX_CLOCK_EMIOS_CHANNEL),
    (rtems_interrupt_handler) Clock_isr,
    NULL
  );
  RTEMS_CHECK_SC_VOID( sc, "remove clock interrupt handler");
}

static uint32_t mpc55xx_clock_nanoseconds_since_last_tick( void)
{
  volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL];
  uint64_t c = regs->CCNTR.R;
  union EMIOS_CSR_tag csr = { .R = regs->CSR.R };
  uint64_t k = mpc55xx_clock_factor;

  if (csr.B.FLAG != 0) {
    c = regs->CCNTR.R + regs->CADR.R + 1;
  }

  return (uint32_t) ((c * k) >> 32);
}

#define Clock_driver_support_initialize_hardware() mpc55xx_clock_initialize()

#define Clock_driver_support_install_isr( isr, old_isr) \
  mpc55xx_clock_handler_install(isr,&old_isr)

#define Clock_driver_support_shutdown_hardware() mpc55xx_clock_cleanup()

#define Clock_driver_nanoseconds_since_last_tick \
  mpc55xx_clock_nanoseconds_since_last_tick

/* Include shared source clock driver code */
#include "../../../../libbsp/shared/clockdrv_shell.h"