diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2008-07-14 08:46:06 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2008-07-14 08:46:06 +0000 |
commit | 3c6fe2e7f95f6bff53123df9377b114cadeac874 (patch) | |
tree | fef9ad7a4cd45497a1a84c1b7f9cd103eb258c43 /c/src/lib/libcpu/powerpc/ppc403 | |
parent | corrections in display driver (diff) | |
download | rtems-3c6fe2e7f95f6bff53123df9377b114cadeac874.tar.bz2 |
added haleakala BSP contributed by Michael Hamel
Diffstat (limited to 'c/src/lib/libcpu/powerpc/ppc403')
-rw-r--r-- | c/src/lib/libcpu/powerpc/ppc403/clock/clock_4xx.c | 251 | ||||
-rw-r--r-- | c/src/lib/libcpu/powerpc/ppc403/include/ppc405ex.h | 158 | ||||
-rw-r--r-- | c/src/lib/libcpu/powerpc/ppc403/include/ppc405gp.h | 146 | ||||
-rw-r--r-- | c/src/lib/libcpu/powerpc/ppc403/timer/timer.c | 84 |
4 files changed, 578 insertions, 61 deletions
diff --git a/c/src/lib/libcpu/powerpc/ppc403/clock/clock_4xx.c b/c/src/lib/libcpu/powerpc/ppc403/clock/clock_4xx.c new file mode 100644 index 0000000000..890e75509d --- /dev/null +++ b/c/src/lib/libcpu/powerpc/ppc403/clock/clock_4xx.c @@ -0,0 +1,251 @@ +/* clock.c + * + * This routine initializes the interval timer on the + * PowerPC 405 CPU. The tick frequency is specified by the bsp. + * + * 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-2007. + * 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.com/license/LICENSE. + * + * Modifications for PPC405GP by Dennis Ehlin + * + * Further modifications for PPC405GP/EX by Michael Hamel + * + * $Id$ + */ + +#include <rtems.h> +#include <rtems/clockdrv.h> +#include <rtems/libio.h> +#include <stdlib.h> /* for atexit() */ +#include <rtems/bspIo.h> +#include <ppc405common.h> +#include <libcpu/cpuIdent.h> +#include <bsp/irq.h> + + + +/* PPC405GP */ +#define CPC0_CR1 0xB2 + #define CR1_CETE 0x00800000 + +/* PPC405EX */ +#define SDR0_C405 0x180 + #define SDR_CETE 0x02000000 + +volatile uint32_t Clock_driver_ticks; +static uint32_t pit_value, tick_time; + +void Clock_exit( void ); + +rtems_isr_entry set_vector( /* returns old vector */ + rtems_isr_entry handler, /* isr routine */ + rtems_vector_number vector, /* vector number */ + int type /* RTEMS or RAW intr */ +); + +/* Defined in bspstart.c */ +extern uint32_t bsp_clicks_per_usec; +extern boolean bsp_timer_internal_clock; + +/* + * 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 Handler + */ + +void Clock_isr(void* handle) +{ + Clock_driver_ticks++; + rtems_clock_tick(); +} + +int ClockIsOn(const rtems_irq_connect_data* unused) +{ + return ((mfspr(TCR) & PIE) != 0); +} + + +void ClockOff(const rtems_irq_connect_data* unused) +{ + register uint32_t r; + + r = mfspr(TCR); + mtspr(TCR, r & ~(PIE | ARE) ); +} + +void ClockOn(const rtems_irq_connect_data* unused) +{ + uint32_t iocr, r; + ppc_cpu_id_t cpu; + Clock_driver_ticks = 0; + + cpu = get_ppc_cpu_type(); + if (cpu==PPC_405GP) { + iocr = mfdcr(CPC0_CR1); + if (bsp_timer_internal_clock) iocr &= ~CR1_CETE ;/* timer clocked from system clock */ + else iocr |= CR1_CETE; /* select external timer clock */ + mtdcr(CPC0_CR1,iocr); + } else if (cpu==PPC_405EX) { + mfsdr(SDR0_C405,iocr); + if (bsp_timer_internal_clock) iocr &= ~SDR_CETE ;/* timer clocked from system clock */ + else iocr |= SDR_CETE; /* select external timer clock */ + mtsdr(SDR0_C405,iocr); + } else { + printk("clock.c:unrecognised CPU"); + rtems_fatal_error_occurred(1); + } + + pit_value = rtems_configuration_get_microseconds_per_tick() * bsp_clicks_per_usec; + mtspr(PIT,pit_value); + + tick_time = mfspr(TBL) + pit_value; + r = mfspr(TCR); + mtspr(TCR, r | PIE | ARE); +} + + + +void Install_clock(void (*clock_isr)(void *)) +{ + + /* + * 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 + */ + + rtems_irq_connect_data clockIrqConnData; + + Clock_driver_ticks = 0; + 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); +} + +void +ReInstall_clock(void (*new_clock_isr)(void *)) +{ + uint32_t isrlevel = 0; + rtems_irq_connect_data clockIrqConnData; + + rtems_interrupt_disable(isrlevel); + 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); + clockIrqConnData.on = ClockOn; + clockIrqConnData.off = ClockOff; + clockIrqConnData.isOn = ClockIsOn; + clockIrqConnData.name = BSP_PIT; + clockIrqConnData.hdl = new_clock_isr; + if (!BSP_install_rtems_irq_handler (&clockIrqConnData)) { + printk("Unable to connect Clock Irq handler\n"); + rtems_fatal_error_occurred(1); + } + rtems_interrupt_enable(isrlevel); +} + + +/* + * 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 ); + + /* + * 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; + + if (args!=NULL) { + /* + * 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', ' ')) + Clock_isr(NULL); + else if (args->command == rtems_build_name('N', 'E', 'W', ' ')) + ReInstall_clock(args->buffer); + } + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libcpu/powerpc/ppc403/include/ppc405ex.h b/c/src/lib/libcpu/powerpc/ppc403/include/ppc405ex.h new file mode 100644 index 0000000000..e64fc2d936 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/ppc403/include/ppc405ex.h @@ -0,0 +1,158 @@ + +/* + +Constants for manipulating system registers of PPC 405EX in C + +Michael Hamel ADInstruments May 2008 + +*/ + +#include <libcpu/powerpc-utility.h> +/* Indirect access to Clocking/Power-On registers */ +#define CPR0_DCR_BASE 0x0C +#define cprcfga (CPR0_DCR_BASE+0x0) +#define cprcfgd (CPR0_DCR_BASE+0x1) + +#define mtcpr(reg, d) \ + do { \ + PPC_SET_DEVICE_CONTROL_REGISTER(cprcfga,reg); \ + PPC_SET_DEVICE_CONTROL_REGISTER(cprcfgd,d); \ + } while (0) + +#define mfcpr(reg, d) \ + do { \ + PPC_SET_DEVICE_CONTROL_REGISTER(cprcfga,reg); \ + d = PPC_DEVICE_CONTROL_REGISTER(cprcfgd); \ + } while (0) + + +/* Indirect access to System registers */ +#define SDR_DCR_BASE 0x0E +#define sdrcfga (SDR_DCR_BASE+0x0) +#define sdrcfgd (SDR_DCR_BASE+0x1) + +#define mtsdr(reg, d) \ + do { \ + PPC_SET_DEVICE_CONTROL_REGISTER(sdrcfga,reg); \ + PPC_SET_DEVICE_CONTROL_REGISTER(sdrcfgd,d); \ + } while (0) + +#define mfsdr(reg, d) \ + do { \ + PPC_SET_DEVICE_CONTROL_REGISTER(sdrcfga,reg); \ + d = PPC_DEVICE_CONTROL_REGISTER(sdrcfgd); \ + } while (0) + +/* Indirect access to EBC registers */ +#define EBC_DCR_BASE 0x12 +#define ebccfga (EBC_DCR_BASE+0x0) +#define ebccfgd (EBC_DCR_BASE+0x1) + +#define mtebc(reg, d) \ + do { \ + PPC_SET_DEVICE_CONTROL_REGISTER(ebccfga,reg); \ + PPC_SET_DEVICE_CONTROL_REGISTER(ebccfgd,d); \ + } while (0) + +#define mfebc(reg, d) \ + do { \ + PPC_SET_DEVICE_CONTROL_REGISTER(ebccfga,reg); \ + d = PPC_DEVICE_CONTROL_REGISTER(ebccfgd); \ + } while (0) + +/* EBC DCRs */ +enum { + /* + EBC0_B0CR = 0, + EBC0_B1CR = 1, + EBC0_B2CR = 2, + EBC0_B3CR = 3, + EBC0_B0AP = 0x10, + EBC0_B1AP = 0x11, + EBC0_B2AP = 0x12, + EBC0_B3AP = 0x13, + EBC0_BEAR = 0x20, + EBC0_BESR = 0x21, + EBC0_CFG = 0x23, + */ + EBC0_CID = 0x24 +}; + +enum { + SDR0_UART0 = 0x120, + SDR0_UART1 = 0x121, + SDR0_C405 = 0x180, + SDR0_MALTBL = 0x280, + SDR0_MALRBL = 0x2A0, + SDR0_MALTBS = 0x2C0, + SDR0_MALRBS = 0x2E0 +}; + + +/* Memory-mapped registers */ + + +/*======================= Ethernet =================== */ + + +typedef struct EthernetRegisters_EX { + uint32_t mode0; + uint32_t mode1; + uint32_t xmtMode0; + uint32_t xmtMode1; + uint32_t rcvMode; + uint32_t intStatus; + uint32_t intEnable; + uint32_t addrHi; + uint32_t addrLo; + uint32_t VLANTPID; + uint32_t VLANTCI; + uint32_t pauseTimer; + uint32_t multicastAddr[2]; + uint32_t multicastMask[2]; + uint32_t unused[4]; + uint32_t lastSrcLo; + uint32_t lastSrcHi; + uint32_t IPGap; + uint32_t STAcontrol; + uint32_t xmtReqThreshold; + uint32_t rcvWatermark; + uint32_t bytesXmtd; + uint32_t bytesRcvd; + uint32_t unused2; + uint32_t revID; + uint32_t unused3[2]; + uint32_t indivHash[8]; + uint32_t groupHash[8]; + uint32_t xmtPause; +} EthernetRegisters_EX; + +enum { + EMAC0Address = 0xEF600900, + EMAC1Address = 0xEF600A00 +}; + + +typedef struct GPIORegisters { + uint32_t OR; + uint32_t GPIO_TCR; /* Note that TCR is defined as a DCR name */ + uint32_t OSRL; + uint32_t OSRH; + uint32_t TSRL; + uint32_t TSRH; + uint32_t ODR; + uint32_t IR; + uint32_t RR1; + uint32_t RR2; + uint32_t RR3; + uint32_t unknown; + uint32_t ISR1L; + uint32_t ISR1H; + uint32_t ISR2L; + uint32_t ISR2H; + uint32_t ISR3L; + uint32_t ISR3H; +} GPIORegisters; + +enum { GPIOAddress = 0xEF600800 }; + diff --git a/c/src/lib/libcpu/powerpc/ppc403/include/ppc405gp.h b/c/src/lib/libcpu/powerpc/ppc403/include/ppc405gp.h new file mode 100644 index 0000000000..814f18d046 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/ppc403/include/ppc405gp.h @@ -0,0 +1,146 @@ + + +/* SDRAM DCRs */ +enum { + SDRAM0_BESR0 = 0, + SDRAM0_BESR1 = 8, + SDRAM0_BEAR = 0x10, + SDRAM0_CFG = 0x20, + SDRAM0_STATUS = 0x24, + SDRAM0_RTR = 0x30, + SDRAM0_PMIT = 0x34, + SDRAM0_TR = 0x80 +}; + + +/* EBC DCRs */ +enum { + EBC0_B0CR = 0, + EBC0_B1CR = 1, + EBC0_B2CR = 2, + EBC0_B3CR = 3, + EBC0_B4CR = 4, + EBC0_B5CR = 5, + EBC0_B6CR = 6, + EBC0_B7CR = 7, + EBC0_B0AP = 0x10, + EBC0_B1AP = 0x11, + EBC0_B2AP = 0x12, + EBC0_B3AP = 0x13, + EBC0_B4AP = 0x14, + EBC0_B5AP = 0x15, + EBC0_B6AP = 0x16, + EBC0_B7AP = 0x17, + EBC0_BEAR = 0x20, + EBC0_BESR0 = 0x21, + EBC0_BESR1 = 0x22, + EBC0_CFG = 0x23 +}; + +/* Memory-mapped registers */ + +typedef struct EthernetRegisters_GP { + uint32_t mode0; + uint32_t mode1; + uint32_t xmtMode0; + uint32_t xmtMode1; + uint32_t rcvMode; + uint32_t intStatus; + uint32_t intEnable; + uint32_t addrHi; + uint32_t addrLo; + uint32_t VLANTPID; + uint32_t VLANTCI; + uint32_t pauseTimer; + uint32_t indivHash[4]; + uint32_t groupHash[4]; + uint32_t lastSrcLo; + uint32_t lastSrcHi; + uint32_t IPGap; + uint32_t STAcontrol; + uint32_t xmtReqThreshold; + uint32_t rcvWatermark; + uint32_t bytesXmtd; + uint32_t bytesRcvd; +} EthernetRegisters_GP; + +enum { EMACAddress = 0xEF600800 }; + +enum { + // Mode 0 bits + kEMACRxIdle = 0x80000000, + kEMACTxIdle = 0x40000000, + kEMACSoftRst = 0x20000000, + kEMACTxEnable = 0x10000000, + kEMACRxEnable = 0x08000000, + + // Mode 1 bits + kEMACFullDuplex = 0x80000000, + kEMACIgnoreSQE = 0x01000000, + kEMAC100MBbps = 0x00400000, + kEMAC4KRxFIFO = 0x00300000, + kEMAC2KTxFIFO = 0x00080000, + kEMACTx0Multi = 0x00008000, + kEMACTxDependent= 0x00014000, + + // Tx mode bits + kEMACNewPacket0 = 0x80000000, + kEMACNewPacket1 = 0x40000000, + + // Receive mode bits + kEMACStripPadding = 0x80000000, + kEMACStripFCS = 0x40000000, + kEMACRcvRunts = 0x20000000, + kEMACRcvFCSErrs = 0x10000000, + kEMACRcvOversize = 0x08000000, + kEMACPromiscRcv = 0x01000000, + kEMACPromMultRcv = 0x00800000, + kEMACIndivRcv = 0x00400000, + kEMACHashRcv = 0x00200000, + kEMACBrcastRcv = 0x00100000, + kEMACMultcastRcv = 0x00080000, + + // Buffer descriptor control bits + kMALTxReady = 0x8000, + kMALRxEmpty = 0x8000, + kMALWrap = 0x4000, + kMALContinuous = 0x2000, + kMALLast = 0x1000, + kMALRxFirst = 0x0800, + kMALInterrupt = 0x0400, + + // EMAC Tx descriptor bits sent + kEMACGenFCS = 0x200, + kEMACGenPad = 0x100, + kEMACInsSrcAddr = 0x080, + kEMACRepSrcAddr = 0x040, + kEMACInsVLAN = 0x020, + kEMACRepVLAN = 0x010, + + // EMAC TX descriptor bits returned + kEMACErrMask = 0x3FF, + kEMACFCSWrong = 0x200, + kEMACBadPrev = 0x100, + kEMACLostCarrier = 0x080, + kEMACDeferred = 0x040, + kEMACCollFail = 0x020, + kEMACLateColl = 0x010, + kEMACMultColl = 0x008, + kEMACOneColl = 0x004, + kEMACUnderrun = 0x002, + kEMACSQEFail = 0x001, + + // EMAC Rx descriptor bits returned + kEMACOverrun = 0x200, + kEMACPausePkt = 0x100, + kEMACBadPkt = 0x080, + kEMACRuntPkt = 0x040, + kEMACShortEvt = 0x020, + kEMACAlignErr = 0x010, + kEMACBadFCS = 0x008, + kEMACPktLong = 0x004, + kEMACPktOOR = 0x002, + kEMACPktIRL = 0x001 +}; + + diff --git a/c/src/lib/libcpu/powerpc/ppc403/timer/timer.c b/c/src/lib/libcpu/powerpc/ppc403/timer/timer.c index 25bd3659d6..8eed54468e 100644 --- a/c/src/lib/libcpu/powerpc/ppc403/timer/timer.c +++ b/c/src/lib/libcpu/powerpc/ppc403/timer/timer.c @@ -1,6 +1,6 @@ /* timer.c * - * This file manages the interval timer on the PowerPC 403*. + * This file manages the interval timer on the PowerPC 405. * We shall use the bottom 32 bits of the timebase register, * * NOTE: It is important that the timer start/stop overhead be @@ -32,85 +32,47 @@ * * Modifications for PPC405GP by Dennis Ehlin * + * Further mods for PPC405EX/EXr by Michael Hamel + * * $Id$ * */ #include <rtems.h> +#include <libcpu/powerpc-utility.h> -static volatile uint32_t Timer_starting; -static rtems_boolean Timer_driver_Find_average_overhead; - -/* - * This is so small that this code will be reproduced where needed. - */ -static inline uint32_t get_itimer(void) -{ - uint32_t ret; - -#ifndef ppc405 - asm volatile ("mfspr %0, 0x3dd" : "=r" ((ret))); /* TBLO */ -#else /* ppc405 */ -/* asm volatile ("mfspr %0, 0x3dd" : "=r" ((ret))); TBLO */ - - asm volatile ("mfspr %0, 0x10c" : "=r" ((ret))); /* 405GP TBL */ -#endif /* ppc405 */ +extern uint32_t bsp_timer_least_valid; +extern uint32_t bsp_timer_average_overhead; - return ret; -} +static volatile uint32_t startedAt; +static rtems_boolean subtractOverhead; void Timer_initialize() { - uint32_t iocr; - -#ifndef ppc405 - asm volatile ("mfdcr %0, 0xa0" : "=r" (iocr)); /* IOCR */ - iocr &= ~4; - iocr |= 4; /* Select external timer clock */ - asm volatile ("mtdcr 0xa0, %0" : "=r" (iocr) : "0" (iocr)); /* IOCR */ -#else /* ppc405 */ - asm volatile ("mfdcr %0, 0x0b2" : "=r" (iocr)); /*405GP CPC0_CR1 */ -/* asm volatile ("mfdcr %0, 0xa0" : "=r" (iocr)); IOCR */ - - /* iocr |= 0x800000; select external timer clock CETE*/ - iocr &= ~0x800000; /* timer clocked from system clock CETE*/ - - asm volatile ("mtdcr 0x0b2, %0" : "=r" (iocr) : "0" (iocr)); /* 405GP CPC0_CR1 */ -/* asm volatile ("mtdcr 0xa0, %0" : "=r" (iocr) : "0" (iocr)); IOCR */ -#endif /* ppc405 */ - - Timer_starting = get_itimer(); + /* We are going to rely on clock.c to sort out where the clock comes from */ + startedAt = ppc_time_base(); } int Read_timer() { - uint32_t clicks; - uint32_t total; - extern uint32_t bsp_timer_least_valid; - extern uint32_t bsp_timer_average_overhead; - - clicks = get_itimer(); - - total = clicks - Timer_starting; - - if ( Timer_driver_Find_average_overhead == 1 ) - return total; /* in XXX microsecond units */ - - else { - if ( total < bsp_timer_least_valid ) - return 0; /* below timer resolution */ - return (total - bsp_timer_average_overhead); - } + uint32_t clicks, total; + + clicks = ppc_time_base(); + total = clicks - startedAt; + if ( ! subtractOverhead ) + return total; /* in XXX microsecond units */ + else if ( total < bsp_timer_least_valid ) + return 0; /* below timer resolution */ + else + return (total - bsp_timer_average_overhead); } rtems_status_code Empty_function( void ) { - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; } -void Set_find_average_overhead( - rtems_boolean find_flag -) +void Set_find_average_overhead( rtems_boolean find_flag) { - Timer_driver_Find_average_overhead = find_flag; + subtractOverhead = find_flag; } |