summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2011-04-20 20:20:47 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2011-04-20 20:20:47 +0000
commitcb4c90b227661280d5da48ecae0aa62890b55494 (patch)
tree06bda5f63f8a254bc508573c835245d4a1a48cae /c
parent2011-04-20 Rohan Kangralkar <rkangral@ece.neu.edu> (diff)
downloadrtems-cb4c90b227661280d5da48ecae0aa62890b55494.tar.bz2
2011-04-20 Rohan Kangralkar <rkangral@ece.neu.edu>
PR 1781/bsps * bf52x/include: Added additional MMR. * bf52x/interrupt: The BF52X processors have a different System interrupt controller than present in the 53X range of processors. The 52X have 8 interrupt assignment registers. The implementation uses tables to increase predictability. * serial/uart.?: Added DMA based and interrupt based transfer support. The uart code used a single ISR for TX and RX and tried to identify and multiplex inside the ISR. In the new code the type of interrupt is identified by the central ISR dispatcher bf52x/interrupt or interrupt/. This simplifies the UART ISR.
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libcpu/bfin/ChangeLog14
-rw-r--r--c/src/lib/libcpu/bfin/Makefile.am27
-rw-r--r--c/src/lib/libcpu/bfin/bf52x/include/bf52x.h133
-rw-r--r--c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.c643
-rw-r--r--c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.h146
-rw-r--r--c/src/lib/libcpu/bfin/configure.ac4
-rw-r--r--c/src/lib/libcpu/bfin/include/sicRegs.h8
-rw-r--r--c/src/lib/libcpu/bfin/preinstall.am23
-rw-r--r--c/src/lib/libcpu/bfin/serial/uart.c520
-rw-r--r--c/src/lib/libcpu/bfin/serial/uart.h113
10 files changed, 1467 insertions, 164 deletions
diff --git a/c/src/lib/libcpu/bfin/ChangeLog b/c/src/lib/libcpu/bfin/ChangeLog
index 305088920d..102622b88d 100644
--- a/c/src/lib/libcpu/bfin/ChangeLog
+++ b/c/src/lib/libcpu/bfin/ChangeLog
@@ -1,3 +1,17 @@
+2011-04-20 Rohan Kangralkar <rkangral@ece.neu.edu>
+
+ PR 1781/bsps
+ * bf52x/include: Added additional MMR.
+ * bf52x/interrupt: The BF52X processors have a different
+ System interrupt controller than present in the 53X range of
+ processors. The 52X have 8 interrupt assignment registers. The
+ implementation uses tables to increase predictability.
+ * serial/uart.?: Added DMA based and interrupt based transfer
+ support. The uart code used a single ISR for TX and RX and tried
+ to identify and multiplex inside the ISR. In the new code the
+ type of interrupt is identified by the central ISR dispatcher
+ bf52x/interrupt or interrupt/. This simplifies the UART ISR.
+
2011-02-11 Ralf Corsépius <ralf.corsepius@rtems.org>
* timer/timer.c:
diff --git a/c/src/lib/libcpu/bfin/Makefile.am b/c/src/lib/libcpu/bfin/Makefile.am
index 3eb65cce94..6e9fb3ec32 100644
--- a/c/src/lib/libcpu/bfin/Makefile.am
+++ b/c/src/lib/libcpu/bfin/Makefile.am
@@ -10,9 +10,31 @@ EXTRA_DIST =
noinst_PROGRAMS =
+include_bspdir = $(includedir)/bsp
include_libcpudir = $(includedir)/libcpu
+
+include_bsp_HEADERS =
include_libcpu_HEADERS =
+
+############
+# Start of bf52x files
+if bf52x
+
+include_HEADERS = bf52x/include/bf52x.h
+
+## INTERRUPT
+include_bsp_HEADERS += bf52x/interrupt/interrupt.h
+noinst_PROGRAMS += bf52x/interrupt.rel
+bf52x_interrupt_rel_SOURCES = bf52x/interrupt/interrupt.c \
+ bf52x/interrupt/interrupt.h
+bf52x_interrupt_rel_CPPFLAGS = $(AM_CPPFLAGS)
+bf52x_interrupt_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+endif
+# endof bf52x
+############
+
include_libcpu_HEADERS += include/bf533.h
include_libcpu_HEADERS += include/bf537.h
include_libcpu_HEADERS += include/cecRegs.h
@@ -47,12 +69,17 @@ mmu_rel_SOURCES = mmu/mmu.c
mmu_rel_CPPFLAGS = $(AM_CPPFLAGS)
mmu_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+if bf52x
+
+else
include_libcpu_HEADERS += interrupt/interrupt.h
noinst_PROGRAMS += interrupt.rel
interrupt_rel_SOURCES = interrupt/interrupt.c
interrupt_rel_CPPFLAGS = $(AM_CPPFLAGS)
interrupt_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+endif
+
noinst_PROGRAMS += clock.rel
clock_rel_SOURCES = clock/clock.c
clock_rel_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/c/src/lib/libcpu/bfin/bf52x/include/bf52x.h b/c/src/lib/libcpu/bfin/bf52x/include/bf52x.h
new file mode 100644
index 0000000000..460fd388bd
--- /dev/null
+++ b/c/src/lib/libcpu/bfin/bf52x/include/bf52x.h
@@ -0,0 +1,133 @@
+/**
+ *@file bf52x.h
+ *
+ *@brief
+ * - This file provides the register address for the 52X model. The file is
+ * based on the 533 implementation with some addition to support 52X range of
+ * processors.
+ *
+ * Target: TLL6527v1-0
+ * Compiler:
+ *
+ * COPYRIGHT (c) 2010 by ECE Northeastern University.
+ *
+ * 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
+ *
+ * @author Rohan Kangralkar, ECE, Northeastern University
+ * (kangralkar.r@husky.neu.edu)
+ *
+ * LastChange:
+ * $Id$
+ *
+ */
+
+#ifndef _BF52X_H_
+#define _BF52X_H_
+
+/* register (or register block) addresses */
+
+#define SIC_BASE_ADDRESS 0xffc00100
+#define WDOG_BASE_ADDRESS 0xffc00200
+#define RTC_BASE_ADDRESS 0xffc00300
+#define UART0_BASE_ADDRESS 0xffc00400
+#define UART1_BASE_ADDRESS 0xffc02000
+#define SPI_BASE_ADDRESS 0xffc00500
+#define TIMER_BASE_ADDRESS 0xffc00600
+#define TIMER_CHANNELS 3
+#define TIMER_PITCH 0x10
+#define TIMER0_BASE_ADDRESS 0xffc00600
+#define TIMER1_BASE_ADDRESS 0xffc00610
+#define TIMER2_BASE_ADDRESS 0xffc00620
+#define TIMER_ENABLE 0xffc00640
+#define TIMER_DISABLE 0xffc00644
+#define TIMER_STATUS 0xffc00648
+#define PORTFIO_BASE_ADDRESS 0xffc00700
+#define SPORT0_BASE_ADDRESS 0xffc00800
+#define SPORT1_BASE_ADDRESS 0xffc00900
+#define EBIU_BASE_ADDRESS 0xffc00a00
+#define DMA_TC_PER 0xffc00b0c
+#define DMA_TC_CNT 0xffc00b10
+#define DMA_BASE_ADDRESS 0xffc00c00
+#define DMA_CHANNELS 8
+#define DMA_PITCH 0x40
+#define DMA0_BASE_ADDRESS 0xffc00c00
+#define DMA1_BASE_ADDRESS 0xffc00c40
+#define DMA2_BASE_ADDRESS 0xffc00c80
+#define DMA3_BASE_ADDRESS 0xffc00cc0
+#define DMA4_BASE_ADDRESS 0xffc00d00
+#define DMA5_BASE_ADDRESS 0xffc00d40
+#define DMA6_BASE_ADDRESS 0xffc00d80
+#define DMA7_BASE_ADDRESS 0xffc00dc0
+#define DMA8_BASE_ADDRESS 0xffc00e00
+#define DMA9_BASE_ADDRESS 0xffc00e40
+#define DMA10_BASE_ADDRESS 0xffc00e80
+#define DMA11_BASE_ADDRESS 0xffc00ec0
+#define MDMA_BASE_ADDRESS 0xffc00e00
+#define MDMA_CHANNELS 2
+#define MDMA_D_S 0x40
+#define MDMA_PITCH 0x80
+#define MDMA0D_BASE_ADDRESS 0xffc00e00
+#define MDMA0S_BASE_ADDRESS 0xffc00e40
+#define MDMA1D_BASE_ADDRESS 0xffc00e80
+#define MDMA1S_BASE_ADDRESS 0xffc00ec0
+#define PPI_BASE_ADDRESS 0xffc01000
+
+
+/* register fields */
+
+#define DMA_TC_PER_MDMA_ROUND_ROBIN_PERIOD_MASK 0xf800
+#define DMA_TC_PER_MDMA_ROUND_ROBIN_PERIOD_SHIFT 11
+#define DMA_TC_PER_DAB_TRAFFIC_PERIOD_MASK 0x0700
+#define DMA_TC_PER_DAB_TRAFFIC_PERIOD_SHIFT 8
+#define DMA_TC_PER_DEB_TRAFFIC_PERIOD_MASK 0x00f0
+#define DMA_TC_PER_DEB_TRAFFIC_PERIOD_SHIFT 4
+#define DMA_TC_PER_DCB_TRAFFIC_PERIOD_MASK 0x000f
+#define DMA_TC_PER_DCB_TRAFFIC_PERIOD_SHIFT 0
+
+#define DMA_TC_CNT_MDMA_ROUND_ROBIN_COUNT_MASK 0xf800
+#define DMA_TC_CNT_MDMA_ROUND_ROBIN_COUNT_SHIFT 11
+#define DMA_TC_CNT_DAB_TRAFFIC_COUNT_MASK 0x0700
+#define DMA_TC_CNT_DAB_TRAFFIC_COUNT_SHIFT 8
+#define DMA_TC_CNT_DEB_TRAFFIC_COUNT_MASK 0x00f0
+#define DMA_TC_CNT_DEB_TRAFFIC_COUNT_SHIFT 4
+#define DMA_TC_CNT_DCB_TRAFFIC_COUNT_MASK 0x000f
+#define DMA_TC_CNT_DCB_TRAFFIC_COUNT_SHIFT 0
+
+#define TIMER_ENABLE_TIMEN2 0x0004
+#define TIMER_ENABLE_TIMEN1 0x0002
+#define TIMER_ENABLE_TIMEN0 0x0001
+
+#define TIMER_DISABLE_TIMDIS2 0x0004
+#define TIMER_DISABLE_TIMDIS1 0x0002
+#define TIMER_DISABLE_TIMDIS0 0x0001
+
+#define TIMER_STATUS_TRUN2 0x00004000
+#define TIMER_STATUS_TRUN1 0x00002000
+#define TIMER_STATUS_TRUN0 0x00001000
+#define TIMER_STATUS_TOVF_ERR2 0x00000040
+#define TIMER_STATUS_TOVF_ERR1 0x00000020
+#define TIMER_STATUS_TOVF_ERR0 0x00000010
+#define TIMER_STATUS_TIMIL2 0x00000004
+#define TIMER_STATUS_TIMIL1 0x00000002
+#define TIMER_STATUS_TIMIL0 0x00000001
+
+/* Core Event Controller vectors */
+
+#define CEC_EMULATION_VECTOR 0
+#define CEC_RESET_VECTOR 1
+#define CEC_NMI_VECTOR 2
+#define CEC_EXCEPTIONS_VECTOR 3
+#define CEC_HARDWARE_ERROR_VECTOR 5
+#define CEC_CORE_TIMER_VECTOR 6
+#define CEC_INTERRUPT_BASE_VECTOR 7
+#define CEC_INTERRUPT_COUNT 9
+
+
+/* System Interrupt Controller vectors */
+
+#define SIC_IAR_COUNT 8
+
+#endif /* _BF52X_H_ */
+
diff --git a/c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.c b/c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.c
new file mode 100644
index 0000000000..32f9b2401e
--- /dev/null
+++ b/c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.c
@@ -0,0 +1,643 @@
+/**
+ *@file interrupt.c
+ *
+ *@brief
+ * - This file implements interrupt dispatcher. Most of the code is taken from
+ * the 533 implementation for blackfin. Since 52X supports 56 line and 2 ISR
+ * registers some portion is written twice.
+ *
+ * Target: TLL6527v1-0
+ * Compiler:
+ *
+ * COPYRIGHT (c) 2010 by ECE Northeastern University.
+ *
+ * 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
+ *
+ * @author Rohan Kangralkar, ECE, Northeastern University
+ * (kangralkar.r@husky.neu.edu)
+ *
+ * LastChange:
+ * $Id$
+ *
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+#include <bsp.h>
+#include <libcpu/cecRegs.h>
+#include <libcpu/sicRegs.h>
+#include "interrupt.h"
+
+#define SIC_IAR_COUNT_SET0 4
+#define SIC_IAR_BASE_ADDRESS_0 0xFFC00150
+
+/**
+ * There are two implementations for the interrupt handler.
+ * 1. INTERRUPT_USE_TABLE: uses tables for finding the right ISR.
+ * 2. Uses link list to find the user ISR.
+ *
+ *
+ * 1. INTERRUPT_USE_TABLE
+ * Space requirement:
+ * - Array to hold CEC masks size: CEC_INTERRUPT_COUNT(9)*(2*int).9*2*4= 72B
+ * - Array to hold isr function pointers IRQ_MAX(56)*sizeof(bfin_isr_t)= 896B
+ * - Array for bit twidlling 32 bytes.
+ * - Global Mask 8 bytes.
+ * - Total = 1008 Bytes Aprox
+ *
+ * Time requirements
+ * The worst case time is about the same for jumping to the user ISR. With a
+ * variance of one conditional statement.
+ *
+ * 2. Using link list.
+ * Space requirement:
+ * - Array to hold CEC mask CEC_INTERRUPT_COUNT(9)*(sizeof(vectors)).
+ * 9*3*4= 108B
+ * - Array to hold isr IRQ_MAX(56)*sizeof(bfin_isr_t) The structure has
+ * additional pointers 56*7*4=1568B
+ * - Global Mask 8 bytes.
+ * Total = 1684.
+ * Time requirements
+ * In the worst case all the lines can be on one CEC line to 56 entries have
+ * to be traversed to find the right user ISR.
+ * But this implementation has benefit of being flexible, Providing
+ * additional user assigned priority. and may consume less space
+ * if all devices are not supported.
+ */
+
+/**
+ * TODO: To place the dispatcher routine code in L1.
+ */
+
+#if INTERRUPT_USE_TABLE
+
+
+/******************************************************************************
+ * Static variables
+ *****************************************************************************/
+/**
+ * @var sic_isr0_mask
+ * @brief copy of the mask of SIC ISR. The SIC ISR is cleared by the device
+ * the relevant SIC_ISRx bit is not cleared unless the interrupt
+ * service routine clears the mechanism that generated interrupt
+ */
+static uint32_t sic_isr0_mask = 0;
+
+/**
+ * @var sic_isr0_mask
+ * @brief copy of the mask of SIC ISR. The SIC ISR is cleared by the device
+ * the relevant SIC_ISRx bit is not cleared unless the interrupt
+ * service routine clears the mechanism that generated interrupt
+ */
+static uint32_t sic_isr1_mask = 0;
+
+
+/**
+ * @var sic_isr
+ * @brief An array of sic register mask for each of the 16 core interrupt lines
+ */
+static struct {
+ uint32_t mask0;
+ uint32_t mask1;
+} vectors[CEC_INTERRUPT_COUNT];
+
+/**
+ * @var ivt
+ * @brief Contains a table of ISR and arguments. The ISR jumps directly to
+ * these ISR.
+ */
+static bfin_isr_t ivt[IRQ_MAX];
+
+/**
+ * http://graphics.stanford.edu/~seander/bithacks.html for more details
+ */
+static const char clz_table[32] =
+{
+ 0, 31, 9, 30, 3, 8, 18, 29, 2, 5, 7, 14, 12, 17,
+ 22, 28, 1, 10, 4, 19, 6, 15, 13, 23, 11, 20, 16,
+ 24, 21, 25, 26, 27
+};
+
+/**
+ * finds the first bit set from the left. look at
+ * http://graphics.stanford.edu/~seander/bithacks.html for more details
+ * @param n
+ * @return
+ */
+static unsigned long clz(unsigned long n)
+{
+ unsigned long c = 0x7dcd629; /* magic constant... */
+
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ n |= (n >> 16);
+ if (n == 0) return 32;
+ n = c + (c * n);
+ return 31 - clz_table[n >> 27]; /* For little endian */
+}
+
+
+
+/**
+ * Centralized Interrupt dispatcher routine. This routine dispatches interrupts
+ * to the user ISR. The priority is according to the blackfin SIC.
+ * The first level of priority is handled in the hardware at the core event
+ * controller. The second level of interrupt is handled according to the line
+ * number that goes in to the SIC.
+ * * SIC_0 has higher priority than SIC 1.
+ * * Inside the SIC the priority is assigned according to the line number.
+ * Lower the line number higher the priority.
+ *
+ * In order to change the interrupt priority we may
+ * 1. change the SIC IAR registers or
+ * 2. Assign priority and extract it inside this function and call the ISR
+ * according tot the priority.
+ *
+ * @param vector IVG number.
+ * @return
+ */
+static rtems_isr interruptHandler(rtems_vector_number vector) {
+ uint32_t mask = 0;
+ int id = 0;
+ /**
+ * Enable for debugging
+ *
+ * static volatile uint32_t spurious_sic0 = 0;
+ * static volatile uint32_t spurious_source = 0;
+ * static volatile uint32_t spurious_sic1 = 0;
+ */
+
+ /**
+ * Extract the vector number relative to the SIC start line
+ */
+ vector -= CEC_INTERRUPT_BASE_VECTOR;
+
+ /**
+ * Check for bounds
+ */
+ if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
+
+ /**
+ * Extract information and execute ISR from SIC 0
+ */
+ mask = *(uint32_t volatile *) SIC_ISR &
+ *(uint32_t volatile *) SIC_IMASK & vectors[vector].mask0;
+ id = clz(mask);
+ if ( SIC_ISR0_MAX > id ) {
+ /** Parameter check */
+ if( NULL != ivt[id].pFunc) {
+ /** Call the relevant function with argument */
+ ivt[id].pFunc( ivt[id].pArg );
+ } else {
+ /**
+ * spurious interrupt we should not be getting this
+ * spurious_sic0++;
+ * spurious_source = id;
+ */
+ }
+ } else {
+ /**
+ * we look at SIC 1
+ */
+ }
+
+
+ /**
+ * Extract information and execute ISR from SIC 1
+ */
+ mask = *(uint32_t volatile *) (SIC_ISR + SIC_ISR_PITCH) &
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) &
+ vectors[vector].mask1;
+ id = clz(mask)+SIC_ISR0_MAX;
+ if ( IRQ_MAX > id ) {
+ /** Parameter Check */
+ if( NULL != ivt[id].pFunc ) {
+ /** Call the relevant function with argument */
+ ivt[id].pFunc( ivt[id].pArg );
+ } else {
+ /**
+ * spurious interrupt we should not be getting this
+ *
+ * spurious_sic1++;
+ * spurious_source = id;
+ */
+ }
+ } else {
+ /**
+ * we continue
+ */
+ }
+
+ }
+}
+
+
+
+/**
+ * This routine registers a new ISR. It will write a new entry to the IVT table
+ * @param isr contains a callback function and source
+ * @return rtems status code
+ */
+rtems_status_code bfin_interrupt_register(bfin_isr_t *isr) {
+ rtems_interrupt_level isrLevel;
+ int id = 0;
+ int position = 0;
+
+ /**
+ * Sanity Check
+ */
+ if ( NULL == isr ){
+ return RTEMS_UNSATISFIED;
+ }
+
+ /**
+ * Sanity check. The register function should at least provide callback func
+ */
+ if ( NULL == isr->pFunc ) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ id = isr->source;
+
+ /**
+ * Parameter Check. We already have a function registered here. First
+ * unregister and then a new function can be allocated.
+ */
+ if ( NULL != ivt[id].pFunc ) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ rtems_interrupt_disable(isrLevel);
+ /**
+ * Assign the new function pointer to the ISR Dispatcher
+ * */
+ ivt[id].pFunc = isr->pFunc;
+ ivt[id].pArg = isr->pArg;
+
+
+ /** find out which isr mask has to be set to enable the interrupt */
+ if ( SIC_ISR0_MAX > id ) {
+ sic_isr0_mask |= 0x1<<id;
+ *(uint32_t volatile *) SIC_IMASK |= 0x1<<id;
+ } else {
+ position = id - SIC_ISR0_MAX;
+ sic_isr1_mask |= 0x1<<position;
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) |= 0x1<<position;
+ }
+
+ rtems_interrupt_enable(isrLevel);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/**
+ * This function unregisters a registered interrupt handler.
+ * @param isr
+ */
+rtems_status_code bfin_interrupt_unregister(bfin_isr_t *isr) {
+ rtems_interrupt_level isrLevel;
+ int id = 0;
+ int position = 0;
+
+ /**
+ * Sanity Check
+ */
+ if ( NULL == isr ){
+ return RTEMS_UNSATISFIED;
+ }
+
+ id = isr->source;
+
+ rtems_interrupt_disable(isrLevel);
+ /**
+ * Assign the new function pointer to the ISR Dispatcher
+ * */
+ ivt[id].pFunc = NULL;
+ ivt[id].pArg = NULL;
+
+
+ /** find out which isr mask has to be set to enable the interrupt */
+ if ( SIC_ISR0_MAX > id ) {
+ sic_isr0_mask &= ~(0x1<<id);
+ *(uint32_t volatile *) SIC_IMASK &= ~(0x1<<id);
+ } else {
+ position = id - SIC_ISR0_MAX;
+ sic_isr1_mask &= ~(0x1<<position);
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) &= ~(0x1<<position);
+ }
+
+ rtems_interrupt_enable(isrLevel);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+
+
+/**
+ * blackfin interrupt initialization routine. It initializes the bfin ISR
+ * dispatcher. It will also create SIC CEC map which will be used for
+ * identifying the ISR.
+ */
+void bfin_interrupt_init(void) {
+ int source;
+ int vector;
+ uint32_t r;
+ int i;
+ int j;
+
+ *(uint32_t volatile *) SIC_IMASK = 0;
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) = 0;
+
+ memset(vectors, 0, sizeof(vectors));
+ /* build mask0 showing what SIC sources drive each CEC vector */
+ source = 0;
+
+ /**
+ * The bf52x has 8 IAR registers but they do not have a constant pitch.
+ *
+ */
+ for (i = 0; i < SIC_IAR_COUNT; i++) {
+ if ( SIC_IAR_COUNT_SET0 > i ) {
+ r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS + i * SIC_IAR_PITCH);
+ } else {
+ r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS_0 +
+ ((i-SIC_IAR_COUNT_SET0) * SIC_IAR_PITCH));
+ }
+
+ for (j = 0; j < 8; j++) {
+ vector = r & 0x0f;
+ if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
+ /* install our local handler */
+ if (vectors[vector].mask0 == 0 && vectors[vector].mask1 == 0){
+ set_vector(interruptHandler, vector + CEC_INTERRUPT_BASE_VECTOR, 1);
+ }
+ if ( SIC_ISR0_MAX > source ) {
+ vectors[vector].mask0 |= (1 << source);
+ } else {
+ vectors[vector].mask1 |= (1 << (source - SIC_ISR0_MAX));
+ }
+ }
+ r >>= 4;
+ source++;
+ }
+ }
+}
+
+
+
+
+
+#else
+
+static struct {
+ uint32_t mask0;
+ uint32_t mask1;
+ bfin_isr_t *head;
+} vectors[CEC_INTERRUPT_COUNT];
+
+static uint32_t globalMask0;
+static uint32_t globalMask1;
+
+static rtems_isr interruptHandler(rtems_vector_number vector) {
+ bfin_isr_t *isr = NULL;
+ uint32_t sourceMask0 = 0;
+ uint32_t sourceMask1 = 0;
+ rtems_interrupt_level isrLevel;
+
+ rtems_interrupt_disable(isrLevel);
+ vector -= CEC_INTERRUPT_BASE_VECTOR;
+ if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
+ isr = vectors[vector].head;
+ sourceMask0 = *(uint32_t volatile *) SIC_ISR &
+ *(uint32_t volatile *) SIC_IMASK;
+ sourceMask1 = *(uint32_t volatile *) (SIC_ISR + SIC_ISR_PITCH) &
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH);
+ while (isr) {
+ if ((sourceMask0 & isr->mask0) || (sourceMask1 & isr->mask1)) {
+ isr->isr(isr->_arg);
+ sourceMask0 = *(uint32_t volatile *) SIC_ISR &
+ *(uint32_t volatile *) SIC_IMASK;
+ sourceMask1 = *(uint32_t volatile *) (SIC_ISR + SIC_ISR_PITCH) &
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH);
+ }
+ isr = isr->next;
+ }
+ }
+ rtems_interrupt_enable(isrLevel);
+}
+
+/**
+ * Initializes the interrupt module
+ */
+void bfin_interrupt_init(void) {
+ int source;
+ int vector;
+ uint32_t r;
+ int i;
+ int j;
+
+ globalMask0 = ~(uint32_t) 0;
+ globalMask1 = ~(uint32_t) 0;
+ *(uint32_t volatile *) SIC_IMASK = 0;
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) = 0;
+
+ memset(vectors, 0, sizeof(vectors));
+ /* build mask0 showing what SIC sources drive each CEC vector */
+ source = 0;
+
+ /**
+ * The bf52x has 8 IAR registers but they do not have a constant pitch.
+ *
+ */
+ for (i = 0; i < SIC_IAR_COUNT; i++) {
+ if ( SIC_IAR_COUNT_SET0 > i ) {
+ r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS + i * SIC_IAR_PITCH);
+ } else {
+ r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS_0 +
+ ((i-SIC_IAR_COUNT_SET0) * SIC_IAR_PITCH));
+ }
+ for (j = 0; j < 8; j++) {
+ vector = r & 0x0f;
+ if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
+ /* install our local handler */
+ if (vectors[vector].mask0 == 0 && vectors[vector].mask1 == 0){
+ set_vector(interruptHandler, vector + CEC_INTERRUPT_BASE_VECTOR, 1);
+ }
+ if ( SIC_ISR0_MAX > source ) {
+ vectors[vector].mask0 |= (1 << source);
+ } else {
+ vectors[vector].mask1 |= (1 << (source - SIC_ISR0_MAX));
+ }
+ }
+ r >>= 4;
+ source++;
+ }
+ }
+}
+
+/* modify SIC_IMASK based on ISR list for a particular CEC vector */
+static void setMask(uint32_t vector) {
+ bfin_isr_t *isr = NULL;
+ uint32_t mask = 0;
+ uint32_t r = 0;
+
+ mask = 0;
+ isr = vectors[vector].head;
+ while (isr) {
+ mask |= isr->mask0;
+ isr = isr->next;
+ }
+ r = *(uint32_t volatile *) SIC_IMASK;
+ r &= ~vectors[vector].mask0;
+ r |= mask;
+ r &= globalMask0;
+ *(uint32_t volatile *) SIC_IMASK = r;
+
+
+ mask = 0;
+ isr = vectors[vector].head;
+ while (isr) {
+ mask |= isr->mask1;
+ isr = isr->next;
+ }
+ r = *(uint32_t volatile *) (SIC_IMASK+ SIC_IMASK_PITCH);
+ r &= ~vectors[vector].mask1;
+ r |= mask;
+ r &= globalMask1;
+ *(uint32_t volatile *) (SIC_IMASK+ SIC_IMASK_PITCH) = r;
+}
+
+/* add an ISR to the list for whichever vector it belongs to */
+rtems_status_code bfin_interrupt_register(bfin_isr_t *isr) {
+ bfin_isr_t *walk;
+ rtems_interrupt_level isrLevel;
+
+ /* find the appropriate vector */
+ for (isr->vector = 0; isr->vector < CEC_INTERRUPT_COUNT; isr->vector++)
+ if ( (vectors[isr->vector].mask0 & (1 << isr->source) ) || \
+ (vectors[isr->vector].mask1 & (1 << (isr->source - SIC_ISR0_MAX)) ))
+ break;
+ if (isr->vector < CEC_INTERRUPT_COUNT) {
+ isr->next = NULL;
+ isr->mask0 = 0;
+ isr->mask1 = 0;
+ rtems_interrupt_disable(isrLevel);
+ /* find the current end of the list */
+ walk = vectors[isr->vector].head;
+ while (walk && walk->next)
+ walk = walk->next;
+ /* append new isr to list */
+ if (walk)
+ walk->next = isr;
+ else
+ vectors[isr->vector].head = isr;
+ rtems_interrupt_enable(isrLevel);
+ } else
+ /* we failed, but make vector a legal value so other calls into
+ this module with this isr descriptor won't do anything bad */
+ isr->vector = 0;
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code bfin_interrupt_unregister(bfin_isr_t *isr) {
+ bfin_isr_t *walk, *prev;
+ rtems_interrupt_level isrLevel;
+
+ rtems_interrupt_disable(isrLevel);
+ walk = vectors[isr->vector].head;
+ prev = NULL;
+ /* find this isr in our list */
+ while (walk && walk != isr) {
+ prev = walk;
+ walk = walk->next;
+ }
+ if (walk) {
+ /* if found, remove it */
+ if (prev)
+ prev->next = walk->next;
+ else
+ vectors[isr->vector].head = walk->next;
+ /* fix up SIC_IMASK if necessary */
+ setMask(isr->vector);
+ }
+ rtems_interrupt_enable(isrLevel);
+ return RTEMS_SUCCESSFUL;
+}
+
+void bfin_interrupt_enable(bfin_isr_t *isr, bool enable) {
+ rtems_interrupt_level isrLevel;
+
+ rtems_interrupt_disable(isrLevel);
+ if ( SIC_ISR0_MAX > isr->source ) {
+ isr->mask0 = enable ? (1 << isr->source) : 0;
+ *(uint32_t volatile *) SIC_IMASK |= isr->mask0;
+ } else {
+ isr->mask1 = enable ? (1 << (isr->source - SIC_ISR0_MAX)) : 0;
+ *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) |= isr->mask1;
+ }
+
+ //setMask(isr->vector);
+ rtems_interrupt_enable(isrLevel);
+}
+
+void bfin_interrupt_enable_all(int source, bool enable) {
+ rtems_interrupt_level isrLevel;
+ int vector;
+ bfin_isr_t *walk;
+
+ for (vector = 0; vector < CEC_INTERRUPT_COUNT; vector++)
+ if ( (vectors[vector].mask0 & (1 << source) ) || \
+ (vectors[vector].mask1 & (1 << (source - SIC_ISR0_MAX)) ))
+ break;
+ if (vector < CEC_INTERRUPT_COUNT) {
+ rtems_interrupt_disable(isrLevel);
+ walk = vectors[vector].head;
+ while (walk) {
+ walk->mask0 = enable ? (1 << source) : 0;
+ walk = walk->next;
+ }
+
+ walk = vectors[vector].head;
+ while (walk) {
+ walk->mask1 = enable ? (1 << (source - SIC_ISR0_MAX)) : 0;
+ walk = walk->next;
+ }
+ setMask(vector);
+ rtems_interrupt_enable(isrLevel);
+ }
+}
+
+void bfin_interrupt_enable_global(int source, bool enable) {
+ int vector;
+ rtems_interrupt_level isrLevel;
+
+ for (vector = 0; vector < CEC_INTERRUPT_COUNT; vector++)
+ if ( (vectors[vector].mask0 & (1 << source) ) || \
+ (vectors[vector].mask1 & (1 << (source - SIC_ISR0_MAX)) ))
+ break;
+ if (vector < CEC_INTERRUPT_COUNT) {
+ rtems_interrupt_disable(isrLevel);
+ if ( SIC_ISR0_MAX > source ) {
+ if (enable)
+ globalMask0 |= 1 << source;
+ else
+ globalMask0 &= ~(1 << source);
+ }else {
+ if (enable)
+ globalMask1 |= 1 << (source - SIC_ISR0_MAX);
+ else
+ globalMask1 &= ~(1 << (source - SIC_ISR0_MAX));
+ }
+ setMask(vector);
+ rtems_interrupt_enable(isrLevel);
+ }
+}
+
+#endif
diff --git a/c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.h b/c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.h
new file mode 100644
index 0000000000..2e9c269318
--- /dev/null
+++ b/c/src/lib/libcpu/bfin/bf52x/interrupt/interrupt.h
@@ -0,0 +1,146 @@
+/**
+ *@file interrupt.h
+ *
+ *@brief
+ * - This file implements interrupt dispatcher. The init code is taken from
+ * the 533 implementation for blackfin. Since 52X supports 56 line and 2 ISR
+ * registers some portion is written twice.
+ *
+ * Target: TLL6527v1-0
+ * Compiler:
+ *
+ * COPYRIGHT (c) 2010 by ECE Northeastern University.
+ *
+ * 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
+ *
+ * @author Rohan Kangralkar, ECE, Northeastern University
+ * (kangralkar.r@husky.neu.edu)
+ *
+ * LastChange:
+ * $Id$
+ *
+ */
+
+#ifndef _BFIN_INTERRUPT_H_
+#define _BFIN_INTERRUPT_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The type of interrupts handled by the SIC
+ */
+typedef enum {
+ IRQ_PLL_WAKEUP_INTERRUPT, /* 0 */
+ IRQ_DMA_ERROR_0, /* 1 */
+ IRQ_DMAR0_BLOCK_INTERRUPT, /* 2 */
+ IRQ_DMAR1_BLOCK_INTERRUPT, /* 3 */
+ IRQ_DMAR0_OVERFLOW_ERROR, /* 4 */
+ IRQ_DMAR1_OVERFLOW_ERROR, /* 5 */
+ IRQ_PPI_STATUS, /* 6 */
+ IRQ_MAC_STATUS, /* 7 */
+ IRQ_SPORT0_STATUS, /* 8 */
+ IRQ_SPORT1_STATUS, /* 9 */
+ IRQ_RESERVED_10, /* 10 */
+ IRQ_RESERVED_11, /* 11 */
+ IRQ_UART0_STATUS, /* 12 */
+ IRQ_UART1_STATUS, /* 13 */
+ IRQ_REAL_TIME_CLOCK, /* 14 */
+ IRQ_DMA0_PPI_NFC, /* 15 */
+ IRQ_DMA3_SPORT0_RX, /* 16 */
+ IRQ_DMA4_SPORT0_TX, /* 17 */
+ IRQ_DMA5_SPORT1_RX, /* 18 */
+ IRQ_DMA6_SPORT1_TX, /* 19 */
+ IRQ_TWI_INTERRUPT, /* 20 */
+ IRQ_DMA7_SPI, /* 21 */
+ IRQ_DMA8_UART0_RX, /* 22 */
+ IRQ_DMA9_UART0_TX, /* 23 */
+ IRQ_DMA10_UART1_RX, /* 24 */
+ IRQ_DMA11_UART1_TX, /* 25 */
+ IRQ_OTP, /* 26 */
+ IRQ_GP_COUNTER, /* 27 */
+ IRQ_DMA1_MAC_RX_HOSTDP, /* 28 */
+ IRQ_PORT_H_INTERRUPT_A, /* 29 */
+ IRQ_DMA2_MAC_TX_NFC, /* 30 */
+ IRQ_PORT_H_INTERRUPT_B, /* 31 */
+ SIC_ISR0_MAX, /* 32 ***/
+ IRQ_TIMER0 = SIC_ISR0_MAX, /* 32 */
+ IRQ_TIMER1, /* 33 */
+ IRQ_TIMER2, /* 34 */
+ IRQ_TIMER3, /* 35 */
+ IRQ_TIMER4, /* 36 */
+ IRQ_TIMER5, /* 37 */
+ IRQ_TIMER6, /* 38 */
+ IRQ_TIMER7, /* 39 */
+ IRQ_PORT_G_INTERRUPT_A, /* 40 */
+ IRQ_PORT_G_INTERRUPT_B, /* 41 */
+ IRQ_MDMA0_STREAM_0_INTERRUPT, /* 42 */
+ IRQ_MDMA1_STREAM_0_INTERRUPT, /* 43 */
+ IRQ_SOFTWARE_WATCHDOG_INTERRUPT, /* 44 */
+ IRQ_PORT_F_INTERRUPT_A, /* 45 */
+ IRQ_PORT_F_INTERRUPT_B, /* 46 */
+ IRQ_SPI_STATUS, /* 47 */
+ IRQ_NFC_STATUS, /* 48 */
+ IRQ_HOSTDP_STATUS, /* 49 */
+ IRQ_HOREAD_DONE_INTERRUPT, /* 50 */
+ IRQ_RESERVED_19, /* 51 */
+ IRQ_USB_INT0_INTERRUPT, /* 52 */
+ IRQ_USB_INT1_INTERRUPT, /* 53 */
+ IRQ_USB_INT2_INTERRUPT, /* 54 */
+ IRQ_USB_DMAINT, /* 55 */
+ IRQ_MAX, /* 56 */
+} e_isr_t;
+
+
+
+
+/* source is the source to the SIC (the bit number in SIC_ISR). isr is
+ the function that will be called when the interrupt is active. */
+typedef struct bfin_isr_s {
+#if INTERRUPT_USE_TABLE
+ e_isr_t source;
+ void (*pFunc)(void *arg);
+ void *pArg;
+ int priority; /** not used */
+#else
+ int source;
+ void (*isr)(void *arg);
+ void *_arg;
+ /* the following are for internal use only */
+ uint32_t mask0;
+ uint32_t mask1;
+ uint32_t vector;
+ struct bfin_isr_s *next;
+#endif
+} bfin_isr_t;
+
+/**
+ * This routine registers a new ISR. It will write a new entry to the IVT table
+ * @param isr contains a callback function and source
+ * @return rtems status code
+ */
+rtems_status_code bfin_interrupt_register(bfin_isr_t *isr);
+
+/**
+ * This function unregisters a registered interrupt handler.
+ * @param isr
+ */
+rtems_status_code bfin_interrupt_unregister(bfin_isr_t *isr);
+
+/**
+ * blackfin interrupt initialization routine. It initializes the bfin ISR
+ * dispatcher. It will also create SIC CEC map which will be used for
+ * identifying the ISR.
+ */
+void bfin_interrupt_init(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BFIN_INTERRUPT_H_ */
+
diff --git a/c/src/lib/libcpu/bfin/configure.ac b/c/src/lib/libcpu/bfin/configure.ac
index 0a5e88214d..0fa523fcd1 100644
--- a/c/src/lib/libcpu/bfin/configure.ac
+++ b/c/src/lib/libcpu/bfin/configure.ac
@@ -24,6 +24,10 @@ RTEMS_PROG_CCAS
RTEMS_CHECK_NETWORKING
AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
+# AM_CONDITIONAL(shared, test "$RTEMS_CPU_MODEL" = "bf52x")
+AM_CONDITIONAL(bf52x, test "$RTEMS_CPU_MODEL" = "bf52x")
+
+
RTEMS_AMPOLISH3
# Explicitly list all Makefiles here
diff --git a/c/src/lib/libcpu/bfin/include/sicRegs.h b/c/src/lib/libcpu/bfin/include/sicRegs.h
index 185bd5f09a..0c52622318 100644
--- a/c/src/lib/libcpu/bfin/include/sicRegs.h
+++ b/c/src/lib/libcpu/bfin/include/sicRegs.h
@@ -16,8 +16,14 @@
/* register addresses */
#define SIC_IMASK (SIC_BASE_ADDRESS + 0x000c)
+#define SIC_IMASK_PITCH (0x40)
+
+#define SIC_ISR (SIC_BASE_ADDRESS + 0x0020)
+#define SIC_ISR_PITCH (0x40)
+
#define SIC_IAR_BASE_ADDRESS (SIC_BASE_ADDRESS + 0x0010)
#define SIC_IAR_PITCH 0x04
+
#define SIC_IAR0 (SIC_BASE_ADDRESS + 0x0010)
#if SIC_IAR_COUNT > 1
#define SIC_IAR1 (SIC_BASE_ADDRESS + 0x0014)
@@ -28,7 +34,7 @@
#if SIC_IAR_COUNT > 3
#define SIC_IAR3 (SIC_BASE_ADDRESS + 0x001c)
#endif
-#define SIC_ISR (SIC_BASE_ADDRESS + 0x0020)
+
#define SIC_IWR (SIC_BASE_ADDRESS + 0x0024)
diff --git a/c/src/lib/libcpu/bfin/preinstall.am b/c/src/lib/libcpu/bfin/preinstall.am
index b14978e4ff..a8b2fa979b 100644
--- a/c/src/lib/libcpu/bfin/preinstall.am
+++ b/c/src/lib/libcpu/bfin/preinstall.am
@@ -13,11 +13,30 @@ all-am: $(PREINSTALL_FILES)
PREINSTALL_FILES =
CLEANFILES = $(PREINSTALL_FILES)
+$(PROJECT_INCLUDE)/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)
+ @: > $(PROJECT_INCLUDE)/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp)
+
+$(PROJECT_INCLUDE)/bsp/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp
+ @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+
$(PROJECT_INCLUDE)/libcpu/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/libcpu
@: > $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
+if bf52x
+$(PROJECT_INCLUDE)/bf52x.h: bf52x/include/bf52x.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bf52x.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bf52x.h
+
+$(PROJECT_INCLUDE)/bsp/interrupt.h: bf52x/interrupt/interrupt.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/interrupt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/interrupt.h
+endif
$(PROJECT_INCLUDE)/libcpu/bf533.h: include/bf533.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/bf533.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/bf533.h
@@ -102,10 +121,12 @@ $(PROJECT_INCLUDE)/libcpu/mmu.h: mmu/mmu.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/mmu.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/mmu.h
+if bf52x
+else
$(PROJECT_INCLUDE)/libcpu/interrupt.h: interrupt/interrupt.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/interrupt.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/interrupt.h
-
+endif
$(PROJECT_INCLUDE)/libcpu/uart.h: serial/uart.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/uart.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/uart.h
diff --git a/c/src/lib/libcpu/bfin/serial/uart.c b/c/src/lib/libcpu/bfin/serial/uart.c
index 0f9ab0f673..2135f7531f 100644
--- a/c/src/lib/libcpu/bfin/serial/uart.c
+++ b/c/src/lib/libcpu/bfin/serial/uart.c
@@ -7,6 +7,9 @@
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
+ * Modified:
+ * $ $Author$ Added interrupt support and DMA support
+ *
* $Id$
*/
@@ -18,9 +21,9 @@
#include <stdlib.h>
#include <libcpu/uartRegs.h>
+#include <libcpu/dmaRegs.h>
#include "uart.h"
-
/* flags */
#define BFIN_UART_XMIT_BUSY 0x01
@@ -28,45 +31,16 @@
static bfin_uart_config_t *uartsConfig;
-static void initializeHardware(int minor) {
- uint16_t divisor;
- char *base;
- uint16_t r;
-
- base = uartsConfig->channels[minor].base_address;
-
- *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0;
-
- if (uartsConfig->channels[minor].force_baud)
- divisor = (uint16_t) (uartsConfig->freq /
- (uartsConfig->channels[minor].force_baud * 16));
- else
- divisor = (uint16_t) (uartsConfig->freq / (9600 * 16));
- *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_DLAB;
- *(uint16_t volatile *) (base + UART_DLL_OFFSET) = (divisor & 0xff);
- *(uint16_t volatile *) (base + UART_DLH_OFFSET) = ((divisor >> 8) & 0xff);
-
- *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_WLS_8;
-
- *(uint16_t volatile *) (base + UART_GCTL_OFFSET) = UART_GCTL_UCEN;
-
- r = *(uint16_t volatile *) (base + UART_LSR_OFFSET);
- r = *(uint16_t volatile *) (base + UART_RBR_OFFSET);
- r = *(uint16_t volatile *) (base + UART_IIR_OFFSET);
-
- return;
-}
-
static int pollRead(int minor) {
int c;
- char *base;
+ uint32_t base;
- base = uartsConfig->channels[minor].base_address;
+ base = uartsConfig->channels[minor].uart_baseAddress;
/* check to see if driver is using interrupts so this call will be
harmless (though non-functional) in case some debug code tries to
use it */
- if (!uartsConfig->channels[minor].use_interrupts &&
+ if (!uartsConfig->channels[minor].uart_useInterrupts &&
*((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_DR)
c = *((uint16_t volatile *) (base + UART_RBR_OFFSET));
else
@@ -75,7 +49,7 @@ static int pollRead(int minor) {
return c;
}
-char bfin_uart_poll_read(int minor) {
+char bfin_uart_poll_read(rtems_device_minor_number minor) {
int c;
do {
@@ -86,9 +60,9 @@ char bfin_uart_poll_read(int minor) {
}
void bfin_uart_poll_write(int minor, char c) {
- char *base;
+ uint32_t base;
- base = uartsConfig->channels[minor].base_address;
+ base = uartsConfig->channels[minor].uart_baseAddress;
while (!(*((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_THRE))
;
@@ -157,44 +131,86 @@ static ssize_t pollWrite(int minor, const char *buf, size_t len) {
return count;
}
-static void enableInterrupts(int minor) {
- char *base;
- base = uartsConfig->channels[minor].base_address;
+/**
+ * Routine to initialize the hardware. It initialize the DMA,
+ * interrupt if required.
+ * @param channel channel information
+ */
+static void initializeHardware(bfin_uart_channel_t *channel) {
+ uint16_t divisor = 0;
+ uint32_t base = 0;
+ uint32_t tx_dma_base = 0;
- *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI |
- UART_IER_ERBFI;
-}
+ if ( NULL == channel ) {
+ return;
+ }
+
+ base = channel->uart_baseAddress;
+ tx_dma_base = channel->uart_txDmaBaseAddress;
+ /**
+ * RX based DMA and interrupt is not supported yet
+ * uint32_t tx_dma_base = 0;
+ *
+ * rx_dma_base = channel->uart_rxDmaBaseAddress;
+ */
-static void disableAllInterrupts(void) {
- int i;
- char *base;
- for (i = 0; i < uartsConfig->num_channels; i++) {
- base = uartsConfig->channels[i].base_address;
- *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0;
+ *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0;
+
+ if ( 0 != channel->uart_baud) {
+ divisor = (uint16_t) (uartsConfig->freq /
+ (channel->uart_baud * 16));
+ } else {
+ divisor = (uint16_t) (uartsConfig->freq / (9600 * 16));
}
-}
-static ssize_t interruptWrite(int minor, const char *buf, size_t len) {
- char *base;
+ *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_DLAB;
+ *(uint16_t volatile *) (base + UART_DLL_OFFSET) = (divisor & 0xff);
+ *(uint16_t volatile *) (base + UART_DLH_OFFSET) = ((divisor >> 8) & 0xff);
- base = uartsConfig->channels[minor].base_address;
+ *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_WLS_8;
- uartsConfig->channels[minor].flags |= BFIN_UART_XMIT_BUSY;
- *(uint16_t volatile *) (base + UART_THR_OFFSET) = *buf;
+ *(uint16_t volatile *) (base + UART_GCTL_OFFSET) = UART_GCTL_UCEN;
- /* one byte written */
- return 1;
+ /**
+ * To clear previous status
+ * divisor is a temp variable here
+ */
+ divisor = *(uint16_t volatile *) (base + UART_LSR_OFFSET);
+ divisor = *(uint16_t volatile *) (base + UART_RBR_OFFSET);
+ divisor = *(uint16_t volatile *) (base + UART_IIR_OFFSET);
+
+ if ( channel->uart_useDma ) {
+ *(uint16_t volatile *)(tx_dma_base + DMA_CONFIG_OFFSET) = 0;
+ *(uint16_t volatile *)(tx_dma_base + DMA_CONFIG_OFFSET) = DMA_CONFIG_DI_EN
+ | DMA_CONFIG_SYNC ;
+ *(uint16_t volatile *)(tx_dma_base + DMA_IRQ_STATUS_OFFSET) |=
+ DMA_IRQ_STATUS_DMA_DONE | DMA_IRQ_STATUS_DMA_ERR;
+
+ } else {
+ /**
+ * We use polling or interrupts only sending one char at a time :(
+ */
+ }
+
+ return;
}
+
+/**
+ * Set the UART attributes.
+ * @param minor
+ * @param termios
+ * @return
+ */
static int setAttributes(int minor, const struct termios *termios) {
- char *base;
+ uint32_t base;
int baud;
uint16_t divisor;
uint16_t lcr;
- base = uartsConfig->channels[minor].base_address;
+ base = uartsConfig->channels[minor].uart_baseAddress;
switch (termios->c_cflag & CBAUD) {
case B0:
baud = 0;
@@ -260,8 +276,8 @@ static int setAttributes(int minor, const struct termios *termios) {
baud = -1;
break;
}
- if (baud > 0 && uartsConfig->channels[minor].force_baud)
- baud = uartsConfig->channels[minor].force_baud;
+ if (baud > 0 && uartsConfig->channels[minor].uart_baud)
+ baud = uartsConfig->channels[minor].uart_baud;
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr = UART_LCR_WLS_5;
@@ -282,8 +298,8 @@ static int setAttributes(int minor, const struct termios *termios) {
lcr |= UART_LCR_PEN | UART_LCR_EPS;
break;
case PARENB | PARODD:
- lcr |= UART_LCR_PEN;
- break;
+ lcr |= UART_LCR_PEN;
+ break;
default:
break;
}
@@ -301,114 +317,326 @@ static int setAttributes(int minor, const struct termios *termios) {
return 0;
}
-void bfin_uart_isr(int source) {
- int i;
- char *base;
- uint16_t uartStat;
- char c;
- uint8_t uartLSR;
-
- /* Just use one ISR and check for all UART interrupt sources in it.
- This is less efficient than making use of the vector to narrow down
- the things we need to check, but not all Blackfins separate the
- UART interrupt sources in the same ways. This way we don't have
- to make this code dependent on the type of Blackfin. */
- for (i = 0; i < uartsConfig->num_channels; i++) {
- if (uartsConfig->channels[i].use_interrupts) {
- base = uartsConfig->channels[i].base_address;
- uartStat = *(uint16_t volatile *) (base + UART_IIR_OFFSET);
- if ((uartStat & UART_IIR_NINT) == 0) {
- switch (uartStat & UART_IIR_STATUS_MASK) {
- case UART_IIR_STATUS_THRE:
- if (uartsConfig->channels[i].termios &&
- (uartsConfig->channels[i].flags & BFIN_UART_XMIT_BUSY)) {
- uartsConfig->channels[i].flags &= ~BFIN_UART_XMIT_BUSY;
- rtems_termios_dequeue_characters(uartsConfig->channels[i].termios,
- 1);
- }
- break;
- case UART_IIR_STATUS_RDR:
- c = *(uint16_t volatile *) (base + UART_RBR_OFFSET);
- if (uartsConfig->channels[i].termios)
- rtems_termios_enqueue_raw_characters(
- uartsConfig->channels[i].termios, &c, 1);
- break;
- case UART_IIR_STATUS_LS:
- uartLSR = *(uint16_t volatile *) (base + UART_LSR_OFFSET);
- /* break, framing error, parity error, or overrun error
- has been detected */
- break;
- default:
- break;
- }
- }
- }
+/**
+ * Interrupt based uart tx routine. The routine writes one character at a time.
+ *
+ * @param minor Minor number to indicate uart number
+ * @param buf Character buffer which stores characters to be transmitted.
+ * @param len Length of buffer to be transmitted.
+ * @return
+ */
+static ssize_t uart_interruptWrite(int minor, const char *buf, size_t len) {
+ uint32_t base = 0;
+ bfin_uart_channel_t* channel = NULL;
+ rtems_interrupt_level isrLevel;
+
+ /**
+ * Sanity Check
+ */
+ if (NULL == buf || NULL == channel || NULL == uartsConfig || minor < 0) {
+ return 0;
}
+
+ channel = &(uartsConfig->channels[minor]);
+
+ if ( NULL == channel || channel->flags & BFIN_UART_XMIT_BUSY ) {
+ return 0;
+ }
+
+ rtems_interrupt_disable(isrLevel);
+
+ base = channel->uart_baseAddress;
+
+ channel->flags |= BFIN_UART_XMIT_BUSY;
+ channel->length = 1;
+ *(uint16_t volatile *) (base + UART_THR_OFFSET) = *buf;
+ *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI;
+
+ rtems_interrupt_enable(isrLevel);
+
+ return 0;
}
-rtems_status_code bfin_uart_initialize(rtems_device_major_number major,
- bfin_uart_config_t *config) {
- rtems_status_code status;
- int i;
+/**
+* This function implements RX ISR
+*/
+void bfinUart_rxIsr(void *_arg)
+{
+ /**
+ * TODO: UART RX ISR implementation.
+ */
- status = RTEMS_SUCCESSFUL;
+}
- rtems_termios_initialize();
- /*
- * Register Device Names
+/**
+ * This function implements TX ISR. The function gets called when the TX FIFO is
+ * empty. It clears the interrupt and dequeues the character. It only tx one
+ * character at a time.
+ *
+ * TODO: error handling.
+ * @param _arg gets the channel information.
+ */
+void bfinUart_txIsr(void *_arg) {
+ bfin_uart_channel_t* channel = NULL;
+ uint32_t base = 0;
+
+ /**
+ * Sanity check
*/
+ if (NULL == _arg) {
+ /** It should never be NULL */
+ return;
+ }
- uartsConfig = config;
- for (i = 0; i < config->num_channels; i++) {
- config->channels[i].termios = NULL;
- config->channels[i].flags = 0;
- initializeHardware(i);
- status = rtems_io_register_name(config->channels[i].name, major, i);
+ channel = (bfin_uart_channel_t *) _arg;
+
+ base = channel->uart_baseAddress;
+
+ *(uint16_t volatile *) (base + UART_IER_OFFSET) &= ~UART_IER_ETBEI;
+ channel->flags &= ~BFIN_UART_XMIT_BUSY;
+
+ rtems_termios_dequeue_characters(channel->termios, channel->length);
+
+ return;
+}
+
+
+
+
+/**
+ * interrupt based DMA write Routine. It configure the DMA to write len bytes.
+ * The DMA supports 64K data only.
+ *
+ * @param minor Identification number of the UART.
+ * @param buf Character buffer pointer
+ * @param len length of data items to be written
+ * @return data already written
+ */
+static ssize_t uart_DmaWrite(int minor, const char *buf, size_t len) {
+ uint32_t base = 0;
+ bfin_uart_channel_t* channel = NULL;
+ uint32_t tx_dma_base = 0;
+ rtems_interrupt_level isrLevel;
+
+ /**
+ * Sanity Check
+ */
+ if ( NULL == buf || 0 > minor || NULL == uartsConfig ) {
+ return 0;
+ }
+
+ channel = &(uartsConfig->channels[minor]);
+
+ /**
+ * Sanity Check and check for transmit busy.
+ */
+ if ( NULL == channel || BFIN_UART_XMIT_BUSY & channel->flags ) {
+ return 0;
+ }
+
+ rtems_interrupt_disable(isrLevel);
+
+ base = channel->uart_baseAddress;
+ tx_dma_base = channel->uart_txDmaBaseAddress;
+
+ channel->flags |= BFIN_UART_XMIT_BUSY;
+ channel->length = len;
+
+ *(uint16_t volatile *) (tx_dma_base + DMA_CONFIG_OFFSET) &= ~DMA_CONFIG_DMAEN;
+ *(uint32_t volatile *) (tx_dma_base + DMA_START_ADDR_OFFSET) = (uint32_t)buf;
+ *(uint16_t volatile *) (tx_dma_base + DMA_X_COUNT_OFFSET) = channel->length;
+ *(uint16_t volatile *) (tx_dma_base + DMA_X_MODIFY_OFFSET) = 1;
+ *(uint16_t volatile *) (tx_dma_base + DMA_CONFIG_OFFSET) |= DMA_CONFIG_DMAEN;
+ *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI;
+
+ rtems_interrupt_enable(isrLevel);
+
+ return 0;
+}
+
+
+/**
+ * RX DMA ISR.
+ * The polling route is used for receiving the characters. This is a place
+ * holder for future implementation.
+ * @param _arg
+ */
+void bfinUart_rxDmaIsr(void *_arg) {
+/**
+ * TODO: Implementation of RX DMA
+ */
+}
+
+/**
+ * This function implements TX dma ISR. It clears the IRQ and dequeues a char
+ * The channel argument will have the base address. Since there are two uart
+ * and both the uarts can use the same tx dma isr.
+ *
+ * TODO: 1. Error checking 2. sending correct length ie after looking at the
+ * number of elements the uart transmitted.
+ *
+ * @param _arg argument passed to the interrupt handler. It contains the
+ * channel argument.
+ */
+void bfinUart_txDmaIsr(void *_arg) {
+ bfin_uart_channel_t* channel = NULL;
+ uint32_t tx_dma_base = 0;
+
+ /**
+ * Sanity check
+ */
+ if (NULL == _arg) {
+ /** It should never be NULL */
+ return;
+ }
+
+ channel = (bfin_uart_channel_t *) _arg;
+
+ tx_dma_base = channel->uart_txDmaBaseAddress;
+
+ if ((*(uint16_t volatile *) (tx_dma_base + DMA_IRQ_STATUS_OFFSET)
+ & DMA_IRQ_STATUS_DMA_DONE)) {
+
+ *(uint16_t volatile *) (tx_dma_base + DMA_IRQ_STATUS_OFFSET)
+ |= DMA_IRQ_STATUS_DMA_DONE | DMA_IRQ_STATUS_DMA_ERR;
+ channel->flags &= ~BFIN_UART_XMIT_BUSY;
+ rtems_termios_dequeue_characters(channel->termios, channel->length);
+ } else {
+ /* UART DMA did not generate interrupt.
+ * This routine must not be called.
+ */
}
- return RTEMS_SUCCESSFUL;
+ return;
+}
+
+/**
+ * Function called during exit
+ */
+void uart_exit(void)
+{
+ /**
+ * TODO: Flushing of quques
+ */
+
}
+/**
+ * Opens the device in different modes. The supported modes are
+ * 1. Polling
+ * 2. Interrupt
+ * 3. DMA
+ * At exit the uart_Exit function will be called to flush the device.
+ *
+ * @param major Major number of the device
+ * @param minor Minor number of the device
+ * @param arg
+ * @return
+ */
rtems_device_driver bfin_uart_open(rtems_device_major_number major,
- rtems_device_minor_number minor,
- void *arg) {
- rtems_status_code sc;
- rtems_libio_open_close_args_t *args;
+ rtems_device_minor_number minor, void *arg) {
+ rtems_status_code sc = RTEMS_NOT_DEFINED;;
+ rtems_libio_open_close_args_t *args = NULL;
+
+ /**
+ * Callback function for polling
+ */
static const rtems_termios_callbacks pollCallbacks = {
- NULL, /* firstOpen */
- NULL, /* lastClose */
- pollRead, /* pollRead */
- pollWrite, /* write */
- setAttributes, /* setAttributes */
- NULL, /* stopRemoteTx */
- NULL, /* startRemoteTx */
- TERMIOS_POLLED /* outputUsesInterrupts */
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ pollRead, /* pollRead */
+ pollWrite, /* write */
+ setAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* outputUsesInterrupts */
};
+
+ /**
+ * Callback function for interrupt based transfers without DMA.
+ * We use interrupts for writing only. For reading we use polling.
+ */
static const rtems_termios_callbacks interruptCallbacks = {
- NULL, /* firstOpen */
- NULL, /* lastClose */
- NULL, /* pollRead */
- interruptWrite, /* write */
- setAttributes, /* setAttributes */
- NULL, /* stopRemoteTx */
- NULL, /* startRemoteTx */
- TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ pollRead, /* pollRead */
+ uart_interruptWrite, /* write */
+ setAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
};
- if (uartsConfig == NULL || minor < 0 || minor >= uartsConfig->num_channels)
+ /**
+ * Callback function for interrupt based DMA transfers.
+ * We use interrupts for writing only. For reading we use polling.
+ */
+ static const rtems_termios_callbacks interruptDmaCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ uart_DmaWrite, /* write */
+ setAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
+ };
+
+
+ if ( NULL == uartsConfig || 0 > minor || minor >= uartsConfig->num_channels) {
return RTEMS_INVALID_NUMBER;
+ }
+
+ /**
+ * Opens device for handling uart send request either by
+ * 1. interrupt with DMA
+ * 2. interrupt based
+ * 3. Polling
+ */
+ if ( uartsConfig->channels[minor].uart_useDma ) {
+ sc = rtems_termios_open(major, minor, arg, &interruptDmaCallbacks);
+ } else {
+ sc = rtems_termios_open(major, minor, arg,
+ uartsConfig->channels[minor].uart_useInterrupts ?
+ &interruptCallbacks : &pollCallbacks);
+ }
- sc = rtems_termios_open(major, minor, arg,
- uartsConfig->channels[minor].use_interrupts ?
- &interruptCallbacks : &pollCallbacks);
args = arg;
uartsConfig->channels[minor].termios = args->iop->data1;
- if (uartsConfig->channels[minor].use_interrupts)
- enableInterrupts(minor);
- atexit(disableAllInterrupts);
+ atexit(uart_exit);
return sc;
}
+
+/**
+* Uart initialization function.
+* @param major major number of the device
+* @param config configuration parameters
+* @return rtems status code
+*/
+rtems_status_code bfin_uart_initialize(rtems_device_major_number major,
+ bfin_uart_config_t *config) {
+ rtems_status_code sc = RTEMS_NOT_DEFINED;
+ int i = 0;
+
+ rtems_termios_initialize();
+
+ /*
+ * Register Device Names
+ */
+ uartsConfig = config;
+ for (i = 0; i < config->num_channels; i++) {
+ config->channels[i].termios = NULL;
+ config->channels[i].flags = 0;
+ initializeHardware(&(config->channels[i]));
+ sc = rtems_io_register_name(config->channels[i].name, major, i);
+ if (RTEMS_SUCCESSFUL != sc) {
+ return sc;
+ }
+ }
+
+ return sc;
+}
diff --git a/c/src/lib/libcpu/bfin/serial/uart.h b/c/src/lib/libcpu/bfin/serial/uart.h
index 87e493bf6d..fbedaf6537 100644
--- a/c/src/lib/libcpu/bfin/serial/uart.h
+++ b/c/src/lib/libcpu/bfin/serial/uart.h
@@ -8,52 +8,133 @@
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
+ * Modified:
+ * $Author$ Added interrupt support and DMA support
+ *
* $Id$
*/
-#ifndef _uart_h_
-#define _uart_h_
+
+#ifndef _UART_H_
+#define _UART_H_
#ifdef __cplusplus
extern "C" {
#endif
-
+/** bfin_uart_channel object
+ */
typedef struct {
- const char *name;
- void *base_address;
- bool use_interrupts;
- int force_baud;
- /* the following are for internal use */
- void *termios;
- uint8_t volatile flags;
+ const char *name; /** Holds name of the device */
+ uint32_t uart_baseAddress; /** UART base address */
+ uint32_t uart_rxDmaBaseAddress; /** RX DMA base address */
+ uint32_t uart_txDmaBaseAddress; /** TX DMA base address */
+ bool uart_useInterrupts; /** are interrupts used */
+ bool uart_useDma; /** is dma used */
+ int uart_baud; /** baud rate, 0 for default */
+
+ void *termios; /** termios associated */
+ uint8_t volatile flags; /** flags for internal use */
+ uint16_t length; /** length for internal use */
} bfin_uart_channel_t;
+
typedef struct {
uint32_t freq;
int num_channels;
bfin_uart_channel_t *channels;
} bfin_uart_config_t;
+/**
+ * @param base_address defines the UART base address
+ * @param source defines the source that caused the interrupt. This argument
+ * will help us in identifying if Rx or TX caused the interrupt.
+ */
+typedef struct {
+ uint32_t base_address;
+ int source;
+} bfin_uart_arg_t;
+
-char bfin_uart_poll_read(int minor);
+
+char bfin_uart_poll_read(rtems_device_minor_number minor);
void bfin_uart_poll_write(int minor, char c);
+
+/**
+* Uart initialization function.
+* @param major major number of the device
+* @param config configuration parameters
+* @return rtems status code
+*/
rtems_status_code bfin_uart_initialize(rtems_device_major_number major,
- bfin_uart_config_t *config);
+ bfin_uart_config_t *config);
+
+
+/**
+ * Opens the device in different modes. The supported modes are
+ * 1. Polling
+ * 2. Interrupt
+ * 3. DMA
+ * At exit the uart_Exit function will be called to flush the device.
+ *
+ * @param major Major number of the device
+ * @param minor Minor number of the device
+ * @param arg
+ * @return
+ */
rtems_device_driver bfin_uart_open(rtems_device_major_number major,
- rtems_device_minor_number minor,
- void *arg);
+ rtems_device_minor_number minor, void *arg);
+
+
+
+/**
+ * This function implements TX dma ISR. It clears the IRQ and dequeues a char
+ * The channel argument will have the base address. Since there are two uart
+ * and both the uarts can use the same tx dma isr.
+ *
+ * TODO: 1. Error checking 2. sending correct length ie after looking at the
+ * number of elements the uart transmitted.
+ *
+ * @param _arg argument passed to the interrupt handler. It contains the
+ * channel argument.
+ */
+void bfinUart_txDmaIsr(void *_arg);
+
+
+
+/**
+ * RX DMA ISR.
+ * The polling route is used for receiving the characters. This is a place
+ * holder for future implementation.
+ * @param _arg
+ */
+void bfinUart_rxDmaIsr(void *_arg);
+
+
+/**
+ * This function implements TX ISR. The function gets called when the TX FIFO is
+ * empty. It clears the interrupt and dequeues the character. It only tx one
+ * character at a time.
+ *
+ * TODO: error handling.
+ * @param _arg gets the channel information.
+ */
+void bfinUart_txIsr(void *_arg);
+
-void bfin_uart_isr(int source);
+/**
+* This function implements RX ISR
+*/
+void bfinUart_rxIsr(void *_arg);
#ifdef __cplusplus
}
#endif
-#endif /* _uart_h_ */
+#endif /* _UART_H_ */