summaryrefslogtreecommitdiffstats
path: root/bsps/bfin
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-03-21 16:38:43 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-03-26 09:15:00 +0200
commite2bd1f653a3bbf969962082b9ccf1e73b0879819 (patch)
tree57a47abb16f0d4bb0536483e53bf659b5a024da2 /bsps/bfin
parentbsp/pc386: Remove unused RTEMS_CPU_MODEL (diff)
downloadrtems-e2bd1f653a3bbf969962082b9ccf1e73b0879819.tar.bz2
bsp/bfin: Move libcpu content to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/bfin')
-rw-r--r--bsps/bfin/TLL6527M/start/interrupt.c642
-rw-r--r--bsps/bfin/bf537Stamp/net/ethernet.c880
-rw-r--r--bsps/bfin/shared/dev/clock.c81
-rw-r--r--bsps/bfin/shared/dev/rtc.c258
-rw-r--r--bsps/bfin/shared/dev/spi.c240
-rw-r--r--bsps/bfin/shared/dev/sport.c2
-rw-r--r--bsps/bfin/shared/dev/timer.c96
-rw-r--r--bsps/bfin/shared/dev/twi.c253
-rw-r--r--bsps/bfin/shared/dev/uart.c528
-rw-r--r--bsps/bfin/shared/interrupt.c196
-rw-r--r--bsps/bfin/shared/mmu.c44
-rw-r--r--bsps/bfin/shared/shared.am8
12 files changed, 3228 insertions, 0 deletions
diff --git a/bsps/bfin/TLL6527M/start/interrupt.c b/bsps/bfin/TLL6527M/start/interrupt.c
new file mode 100644
index 0000000000..1b69046453
--- /dev/null
+++ b/bsps/bfin/TLL6527M/start/interrupt.c
@@ -0,0 +1,642 @@
+/**
+ *@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.org/license
+ *
+ * @author Rohan Kangralkar, ECE, Northeastern University
+ * (kangralkar.r@husky.neu.edu)
+ *
+ * LastChange:
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+#include <bsp.h>
+#include <libcpu/cecRegs.h>
+#include <libcpu/sicRegs.h>
+#include <string.h>
+#include <bsp/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/bsps/bfin/bf537Stamp/net/ethernet.c b/bsps/bfin/bf537Stamp/net/ethernet.c
new file mode 100644
index 0000000000..f08ffdd63b
--- /dev/null
+++ b/bsps/bfin/bf537Stamp/net/ethernet.c
@@ -0,0 +1,880 @@
+/*
+ * RTEMS network driver for Blackfin ethernet controller
+ *
+ * COPYRIGHT (c) 2008 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems/cache.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include <errno.h>
+#include <rtems/error.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <libcpu/dmaRegs.h>
+#include <libcpu/ethernetRegs.h>
+#include <libcpu/ethernet.h>
+
+#if (BFIN_ETHERNET_DEBUG & BFIN_ETHERNET_DEBUG_DUMP_MBUFS)
+#include <rtems/dumpbuf.h>
+#endif
+
+/*
+ * Number of devices supported by this driver
+ */
+#ifndef N_BFIN_ETHERNET
+# define N_BFIN_ETHERNET 1
+#endif
+
+
+/* #define BFIN_IPCHECKSUMS */
+
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+
+/* largest Ethernet frame MAC will handle */
+#define BFIN_ETHERNET_MAX_FRAME_LENGTH 1556
+
+#if MCLBYTES < (BFIN_ETHERNET_MAX_FRAME_LENGTH + 2)
+#error MCLBYTES too small
+#endif
+
+#define BFIN_REG16(base, offset) \
+ (*((uint16_t volatile *) ((char *)(base) + (offset))))
+#define BFIN_REG32(base, offset) \
+ (*((uint32_t volatile *) ((char *)(base) + (offset))))
+
+
+#define DMA_MODE_RX (DMA_CONFIG_FLOW_DESC_LARGE | \
+ (5 << DMA_CONFIG_NDSIZE_SHIFT) | \
+ DMA_CONFIG_WDSIZE_32 | \
+ DMA_CONFIG_WNR | \
+ DMA_CONFIG_DMAEN)
+
+#define DMA_MODE_TX (DMA_CONFIG_FLOW_DESC_LARGE | \
+ (5 << DMA_CONFIG_NDSIZE_SHIFT) | \
+ DMA_CONFIG_WDSIZE_32 | \
+ DMA_CONFIG_DMAEN)
+
+#define DMA_MODE_STATUS (DMA_CONFIG_FLOW_DESC_LARGE | \
+ (5 << DMA_CONFIG_NDSIZE_SHIFT) | \
+ DMA_CONFIG_DI_EN | \
+ DMA_CONFIG_WDSIZE_32 | \
+ DMA_CONFIG_WNR | \
+ DMA_CONFIG_DMAEN)
+
+#define DMA_MODE_STATUS_NO_INT (DMA_CONFIG_FLOW_DESC_LARGE | \
+ (5 << DMA_CONFIG_NDSIZE_SHIFT) | \
+ DMA_CONFIG_WDSIZE_32 | \
+ DMA_CONFIG_WNR | \
+ DMA_CONFIG_DMAEN)
+
+#define DMA_MODE_STATUS_LAST (DMA_CONFIG_FLOW_STOP | \
+ (0 << DMA_CONFIG_NDSIZE_SHIFT) | \
+ DMA_CONFIG_DI_EN | \
+ DMA_CONFIG_WDSIZE_32 | \
+ DMA_CONFIG_WNR | \
+ DMA_CONFIG_DMAEN)
+
+/* five 16 bit words */
+typedef struct dmaDescS {
+ struct dmaDescS *next;
+ void *addr;
+ uint16_t dmaConfig;
+} dmaDescT;
+
+typedef struct {
+ uint32_t status;
+} txStatusT;
+
+#ifdef BFIN_IPCHECKSUMS
+typedef struct {
+ uint16_t ipHeaderChecksum;
+ uint16_t ipPayloadChecksum;
+ uint32_t status;
+} rxStatusT;
+#else
+typedef struct {
+ uint32_t status;
+} rxStatusT;
+#endif
+
+typedef struct {
+ dmaDescT data;
+ dmaDescT status;
+ struct mbuf *m;
+} rxPacketDescT;
+
+typedef struct {
+ dmaDescT data;
+ dmaDescT status;
+ bool inUse;
+ union {
+ uint32_t dummy; /* try to force 32 bit alignment */
+ struct {
+ uint16_t length;
+ char data[BFIN_ETHERNET_MAX_FRAME_LENGTH];
+ } packet;
+ } buffer;
+} txPacketDescT;
+
+
+/* hardware-specific storage */
+struct bfin_ethernetSoftc {
+ struct arpcom arpcom; /* this entry must be first */
+
+ uint32_t sclk;
+
+ void *ethBase;
+ void *rxdmaBase;
+ void *txdmaBase;
+
+ int acceptBroadcast;
+
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ void *status;
+ int rxDescCount;
+ rxPacketDescT *rx;
+ int txDescCount;
+ txPacketDescT *tx;
+
+ bool rmii;
+ int phyAddr;
+
+ /* statistics */
+#ifdef BISON
+ unsigned long Interrupts;
+ unsigned long rxInterrupts;
+ unsigned long rxMissed;
+ unsigned long rxGiant;
+ unsigned long rxNonOctet;
+ unsigned long rxBadCRC;
+ unsigned long rxCollision;
+
+ unsigned long txInterrupts;
+ unsigned long txSingleCollision;
+ unsigned long txMultipleCollision;
+ unsigned long txCollision;
+ unsigned long txDeferred;
+ unsigned long txUnderrun;
+ unsigned long txLateCollision;
+ unsigned long txExcessiveCollision;
+ unsigned long txExcessiveDeferral;
+ unsigned long txLostCarrier;
+ unsigned long txRawWait;
+#endif
+};
+
+static struct bfin_ethernetSoftc ethernetSoftc[N_BFIN_ETHERNET];
+
+
+/* Shut down the interface. */
+static void ethernetStop(struct bfin_ethernetSoftc *sc) {
+ struct ifnet *ifp;
+ void *ethBase;
+
+ ifp = &sc->arpcom.ac_if;
+ ethBase = sc->ethBase;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /* stop the transmitter and receiver. */
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) &= ~(EMAC_OPMODE_TE |
+ EMAC_OPMODE_RE);
+}
+
+/* Show interface statistics */
+static void bfin_ethernetStats(struct bfin_ethernetSoftc *sc) {
+#ifdef BISON
+ printf(" Total Interrupts:%-8lu", sc->Interrupts);
+ printf(" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf(" Giant:%-8lu", sc->rxGiant);
+ printf(" Non-octet:%-8lu\n", sc->rxNonOctet);
+ printf(" Bad CRC:%-8lu", sc->rxBadCRC);
+ printf(" Collision:%-8lu", sc->rxCollision);
+ printf(" Missed:%-8lu\n", sc->rxMissed);
+
+ printf( " Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf( " Deferred:%-8lu", sc->txDeferred);
+ printf(" Lost Carrier:%-8lu\n", sc->txLostCarrier);
+ printf( "Single Collisions:%-8lu", sc->txSingleCollision);
+ printf( "Multiple Collisions:%-8lu", sc->txMultipleCollision);
+ printf("Excessive Collisions:%-8lu\n", sc->txExcessiveCollision);
+ printf( " Total Collisions:%-8lu", sc->txCollision);
+ printf( " Late Collision:%-8lu", sc->txLateCollision);
+ printf(" Underrun:%-8lu\n", sc->txUnderrun);
+ printf( " Raw output wait:%-8lu\n", sc->txRawWait);
+#endif /*BISON*/
+}
+
+void bfin_ethernet_rxdma_isr(int vector) {
+ struct bfin_ethernetSoftc *sc;
+ void *rxdmaBase;
+ uint16_t status;
+ int i;
+
+ for (i = 0; i < N_BFIN_ETHERNET; i++) {
+ sc = &ethernetSoftc[i];
+ rxdmaBase = sc->rxdmaBase;
+ status = BFIN_REG16(rxdmaBase, DMA_IRQ_STATUS_OFFSET);
+ if (status & DMA_IRQ_STATUS_DMA_DONE)
+ rtems_bsdnet_event_send (sc->rxDaemonTid, INTERRUPT_EVENT);
+ BFIN_REG16(rxdmaBase, DMA_IRQ_STATUS_OFFSET) = status;
+ }
+}
+
+void bfin_ethernet_txdma_isr(int vector) {
+ struct bfin_ethernetSoftc *sc;
+ void *txdmaBase;
+ uint16_t status;
+ int i;
+
+ for (i = 0; i < N_BFIN_ETHERNET; i++) {
+ sc = &ethernetSoftc[i];
+ txdmaBase = sc->txdmaBase;
+ status = BFIN_REG16(txdmaBase, DMA_IRQ_STATUS_OFFSET);
+ if (status & DMA_IRQ_STATUS_DMA_DONE)
+ rtems_bsdnet_event_send (sc->txDaemonTid, INTERRUPT_EVENT);
+ BFIN_REG16(txdmaBase, DMA_IRQ_STATUS_OFFSET) = status;
+ }
+}
+
+void bfin_ethernet_mac_isr(int vector) {
+ struct bfin_ethernetSoftc *sc;
+ void *ethBase;
+ int i;
+
+ for (i = 0; i < N_BFIN_ETHERNET; i++) {
+ sc = &ethernetSoftc[i];
+ ethBase = sc->ethBase;
+ BFIN_REG32(ethBase, EMAC_SYSTAT_OFFSET) = ~(uint32_t) 0;
+ }
+}
+
+static bool txFree(struct bfin_ethernetSoftc *sc, int index) {
+ bool freed;
+ txStatusT *status;
+
+ freed = false;
+ if (sc->tx[index].inUse) {
+ status = (txStatusT *) sc->tx[index].status.addr;
+ rtems_cache_invalidate_multiple_data_lines(status, sizeof(*status));
+ if (status->status != 0) {
+ /* update statistics */
+
+ sc->tx[index].inUse = false;
+ freed = true;
+ }
+ }
+
+ return freed;
+}
+
+static void txDaemon(void *arg) {
+ struct bfin_ethernetSoftc *sc;
+ struct ifnet *ifp;
+ struct mbuf *m, *first;
+ rtems_event_set events;
+ void *ethBase;
+ void *txdmaBase;
+ txStatusT *status;
+ int head;
+ int prevHead;
+ int tail;
+ int length;
+ char *ptr;
+
+ sc = (struct bfin_ethernetSoftc *) arg;
+ ifp = &sc->arpcom.ac_if;
+
+ ethBase = sc->ethBase;
+ txdmaBase = sc->txdmaBase;
+ head = 0;
+ prevHead = sc->txDescCount - 1;
+ tail = 0;
+
+ while (1) {
+ /* wait for packet or isr */
+ rtems_bsdnet_event_receive(START_TRANSMIT_EVENT | INTERRUPT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT, &events);
+
+ /* if no descriptors are available, try to free one. To reduce
+ transmit latency only do one here. */
+ if (sc->tx[head].inUse && txFree(sc, tail)) {
+ if (++tail == sc->txDescCount)
+ tail = 0;
+ }
+ /* send packets until the queue is empty or we run out of tx
+ descriptors */
+ while (!sc->tx[head].inUse && (ifp->if_flags & IFF_OACTIVE)) {
+ /* get the next mbuf chain to transmit */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m != NULL) {
+ /* copy packet into our buffer */
+ ptr = sc->tx[head].buffer.packet.data;
+ length = 0;
+ first = m;
+ while (m && length <= BFIN_ETHERNET_MAX_FRAME_LENGTH) {
+ length += m->m_len;
+ if (length <= BFIN_ETHERNET_MAX_FRAME_LENGTH)
+ memcpy(ptr, m->m_data, m->m_len);
+ ptr += m->m_len;
+ m = m->m_next;
+ }
+ m_freem(first); /* all done with mbuf */
+ if (length <= BFIN_ETHERNET_MAX_FRAME_LENGTH) {
+ sc->tx[head].buffer.packet.length = length;
+
+ /* setup tx dma */
+ status = (txStatusT *) sc->tx[head].status.addr;
+ status->status = 0;
+ sc->tx[head].inUse = true;
+ rtems_cache_flush_multiple_data_lines(status, sizeof(*status));
+
+ /* configure dma to stop after sending this packet */
+ sc->tx[head].status.dmaConfig = DMA_MODE_STATUS_LAST;
+ rtems_cache_flush_multiple_data_lines(
+ &sc->tx[head].status.dmaConfig,
+ sizeof(sc->tx[head].status.dmaConfig));
+ rtems_cache_flush_multiple_data_lines(
+ &sc->tx[head].buffer.packet,
+ length + sizeof(uint16_t));
+
+ /* modify previous descriptor to let it continue
+ automatically */
+ sc->tx[prevHead].status.dmaConfig = DMA_MODE_STATUS;
+ rtems_cache_flush_multiple_data_lines(
+ &sc->tx[prevHead].status.dmaConfig,
+ sizeof(sc->tx[prevHead].status.dmaConfig));
+
+ /* restart dma if it stopped before the packet we just
+ added. this is purely to reduce transmit latency,
+ as it would be restarted anyway after this loop (and
+ needs to be, as there's a very small chance that the
+ dma controller had started the last status transfer
+ before the new dmaConfig word was written above and
+ is still doing that status transfer when we check the
+ status below. this will be caught by the check
+ outside the loop as that is guaranteed to run at least
+ once after the last dma complete interrupt. */
+ if ((BFIN_REG16(txdmaBase, DMA_IRQ_STATUS_OFFSET) &
+ DMA_IRQ_STATUS_DMA_RUN) == 0 &&
+ BFIN_REG32(txdmaBase, DMA_NEXT_DESC_PTR_OFFSET) !=
+ (uint32_t) sc->tx[head].data.next) {
+ BFIN_REG16(txdmaBase, DMA_CONFIG_OFFSET) = DMA_MODE_TX;
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) |= EMAC_OPMODE_TE;
+ }
+
+ if (++head == sc->txDescCount)
+ head = 0;
+ if (++prevHead == sc->txDescCount)
+ prevHead = 0;
+
+ /* if no descriptors are available, try to free one */
+ if (sc->tx[head].inUse && txFree(sc, tail)) {
+ if (++tail == sc->txDescCount)
+ tail = 0;
+ }
+ } else {
+ /* dropping packet: too large */
+
+ }
+ } else {
+ /* no packets queued */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+ }
+
+ /* if dma stopped and there's more to do, restart it */
+ if ((BFIN_REG16(txdmaBase, DMA_IRQ_STATUS_OFFSET) &
+ DMA_IRQ_STATUS_DMA_RUN) == 0 &&
+ BFIN_REG32(txdmaBase, DMA_NEXT_DESC_PTR_OFFSET) !=
+ (uint32_t) &sc->tx[head].data) {
+ BFIN_REG16(txdmaBase, DMA_CONFIG_OFFSET) = DMA_MODE_TX;
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) |= EMAC_OPMODE_TE;
+ }
+
+ /* free up any additional tx descriptors */
+ while (txFree(sc, tail)) {
+ if (++tail == sc->txDescCount)
+ tail = 0;
+ }
+ }
+}
+
+
+static void rxDaemon(void *arg) {
+ struct bfin_ethernetSoftc *sc;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct mbuf *rxPacket;
+ void *dataPtr;
+ rtems_event_set events;
+ struct ether_header *eh;
+ rxStatusT *status;
+ uint32_t rxStatus;
+ int head;
+ int prevHead;
+ int length;
+ void *ethBase;
+ void *rxdmaBase;
+
+ sc = (struct bfin_ethernetSoftc *) arg;
+ rxdmaBase = sc->rxdmaBase;
+ ethBase = sc->ethBase;
+ ifp = &sc->arpcom.ac_if;
+ prevHead = sc->rxDescCount - 1;
+ head = 0;
+
+ BFIN_REG16(rxdmaBase, DMA_CONFIG_OFFSET) = DMA_MODE_RX;
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) |= EMAC_OPMODE_RE;
+
+ while (1) {
+ status = sc->rx[head].status.addr;
+ rtems_cache_invalidate_multiple_data_lines(status, sizeof(*status));
+ while (status->status != 0) {
+ if (status->status & EMAC_RX_STAT_RX_OK) {
+ /* get new cluster to replace this one */
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ } else
+ m = NULL;
+
+ rxStatus = status->status;
+ /* update statistics */
+
+
+ if (m) {
+ /* save received packet to send up a little later */
+ rxPacket = sc->rx[head].m;
+ dataPtr = sc->rx[head].data.addr;
+
+ /* setup dma for new cluster */
+ sc->rx[head].m = m;
+ sc->rx[head].data.addr = (void *) (((intptr_t) m->m_data + 3) & ~3);
+ /* invalidate cache for new data buffer, in case any lines
+ are dirty from previous owner */
+ rtems_cache_invalidate_multiple_data_lines(
+ sc->rx[head].data.addr,
+ BFIN_ETHERNET_MAX_FRAME_LENGTH + 2);
+ } else
+ rxPacket = NULL;
+
+ sc->rx[head].status.dmaConfig = DMA_MODE_STATUS_LAST;
+ rtems_cache_flush_multiple_data_lines(&sc->rx[head],
+ sizeof(sc->rx[head]));
+
+ /* mark descriptor as empty */
+ status->status = 0;
+ rtems_cache_flush_multiple_data_lines(&status->status,
+ sizeof(status->status));
+
+ /* allow dma to continue from previous descriptor into this
+ one */
+ sc->rx[prevHead].status.dmaConfig = DMA_MODE_STATUS;
+ rtems_cache_flush_multiple_data_lines(
+ &sc->rx[prevHead].status.dmaConfig,
+ sizeof(sc->rx[prevHead].status.dmaConfig));
+
+ if (rxPacket) {
+ /* send it up */
+ eh = (struct ether_header *) ((intptr_t) dataPtr + 2);
+ rxPacket->m_data = (caddr_t) ((intptr_t) dataPtr + 2 + 14);
+ length = (rxStatus & EMAC_RX_STAT_RX_FRLEN_MASK) >>
+ EMAC_RX_STAT_RX_FRLEN_SHIFT;
+ rxPacket->m_len = length - 14;
+ rxPacket->m_pkthdr.len = rxPacket->m_len;
+ /* invalidate packet buffer cache again (even though it
+ was invalidated prior to giving it to dma engine),
+ because speculative reads might cause cache lines to
+ be filled at any time */
+ rtems_cache_invalidate_multiple_data_lines(eh, length);
+ ether_input(ifp, eh, rxPacket);
+ }
+
+ if (++prevHead == sc->rxDescCount)
+ prevHead = 0;
+ if (++head == sc->rxDescCount)
+ head = 0;
+ status = sc->rx[head].status.addr;
+ rtems_cache_invalidate_multiple_data_lines(status, sizeof(*status));
+ }
+
+ /* if dma stopped before the next descriptor, restart it */
+ if ((BFIN_REG16(rxdmaBase, DMA_IRQ_STATUS_OFFSET) &
+ DMA_IRQ_STATUS_DMA_RUN) == 0 &&
+ BFIN_REG32(rxdmaBase, DMA_NEXT_DESC_PTR_OFFSET) !=
+ (uint32_t) &sc->rx[head].data) {
+ BFIN_REG16(rxdmaBase, DMA_CONFIG_OFFSET) = DMA_MODE_RX;
+ }
+
+ rtems_bsdnet_event_receive(INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT, &events);
+ }
+
+}
+
+/*
+ ******************************************************************
+ * *
+ * Initialization Routines *
+ * *
+ ******************************************************************
+ */
+
+static void resetHardware(struct bfin_ethernetSoftc *sc) {
+ void *ethBase;
+ void *rxdmaBase;
+ void *txdmaBase;
+
+ ethBase = sc->ethBase;
+ rxdmaBase = sc->rxdmaBase;
+ txdmaBase = sc->txdmaBase;
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) = 0;
+ BFIN_REG16(rxdmaBase, DMA_CONFIG_OFFSET) = 0;
+ BFIN_REG16(txdmaBase, DMA_CONFIG_OFFSET) = 0;
+}
+
+static void initializeHardware(struct bfin_ethernetSoftc *sc) {
+ struct ifnet *ifp;
+ struct mbuf *m;
+ unsigned char *hwaddr;
+ int cacheAlignment;
+ int rxStatusSize;
+ int txStatusSize;
+ char *ptr;
+ int i;
+ void *ethBase;
+ void *rxdmaBase;
+ void *txdmaBase;
+ uint32_t divisor;
+
+ ifp = &sc->arpcom.ac_if;
+ ethBase = sc->ethBase;
+ rxdmaBase = sc->rxdmaBase;
+ txdmaBase = sc->txdmaBase;
+
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) = 0;
+ BFIN_REG32(ethBase, EMAC_FLC_OFFSET) = 0;
+ divisor = (sc->sclk / 25000000) / 2 - 1;
+ BFIN_REG32(ethBase, EMAC_SYSCTL_OFFSET) = (divisor <<
+ EMAC_SYSCTL_MDCDIV_SHIFT) |
+ EMAC_SYSCTL_RXDWA;
+#ifdef BFIN_IPCHECKSUMS
+ BFIN_REG32(ethBase, EMAC_SYSCTL_OFFSET) |= EMAC_SYSCTL_RXCKS;
+#endif
+ BFIN_REG32(ethBase, EMAC_SYSTAT_OFFSET) = ~(uint32_t) 0;
+ BFIN_REG32(ethBase, EMAC_RX_IRQE_OFFSET) = 0;
+ BFIN_REG32(ethBase, EMAC_RX_STKY_OFFSET) = ~(uint32_t) 0;
+ BFIN_REG32(ethBase, EMAC_TX_IRQE_OFFSET) = 0;
+ BFIN_REG32(ethBase, EMAC_TX_STKY_OFFSET) = ~(uint32_t) 0;
+ BFIN_REG32(ethBase, EMAC_MMC_RIRQE_OFFSET) = 0;
+ BFIN_REG32(ethBase, EMAC_MMC_RIRQS_OFFSET) = ~(uint32_t) 0;
+ BFIN_REG32(ethBase, EMAC_MMC_TIRQE_OFFSET) = 0;
+ BFIN_REG32(ethBase, EMAC_MMC_TIRQS_OFFSET) = ~(uint32_t) 0;
+ BFIN_REG32(ethBase, EMAC_MMC_CTL_OFFSET) = EMAC_MMC_CTL_MMCE |
+ EMAC_MMC_CTL_CCOR |
+ EMAC_MMC_CTL_RSTC;
+ BFIN_REG32(ethBase, EMAC_MMC_CTL_OFFSET) = EMAC_MMC_CTL_MMCE |
+ EMAC_MMC_CTL_CCOR;
+
+ BFIN_REG16(rxdmaBase, DMA_CONFIG_OFFSET) = 0;
+ BFIN_REG16(txdmaBase, DMA_CONFIG_OFFSET) = 0;
+ BFIN_REG16(rxdmaBase, DMA_X_COUNT_OFFSET) = 0;
+ BFIN_REG16(txdmaBase, DMA_X_COUNT_OFFSET) = 0;
+ BFIN_REG16(rxdmaBase, DMA_X_MODIFY_OFFSET) = 4;
+ BFIN_REG16(txdmaBase, DMA_X_MODIFY_OFFSET) = 4;
+ BFIN_REG16(rxdmaBase, DMA_Y_COUNT_OFFSET) = 0;
+ BFIN_REG16(txdmaBase, DMA_Y_COUNT_OFFSET) = 0;
+ BFIN_REG16(rxdmaBase, DMA_Y_MODIFY_OFFSET) = 0;
+ BFIN_REG16(txdmaBase, DMA_Y_MODIFY_OFFSET) = 0;
+ BFIN_REG16(rxdmaBase, DMA_IRQ_STATUS_OFFSET) = DMA_IRQ_STATUS_DMA_ERR |
+ DMA_IRQ_STATUS_DMA_DONE;
+
+ /* The status structures cannot share cache lines with anything else,
+ including other status structures, so we can safely manage both the
+ processor and DMA writing to them. So this rounds up the structure
+ sizes to a multiple of the cache line size. */
+ cacheAlignment = (int) rtems_cache_get_data_line_size();
+ if (cacheAlignment == 0)
+ cacheAlignment = 1;
+ rxStatusSize = cacheAlignment * ((sizeof(rxStatusT) + cacheAlignment - 1) /
+ cacheAlignment);
+ txStatusSize = cacheAlignment * ((sizeof(txStatusT) + cacheAlignment - 1) /
+ cacheAlignment);
+ /* Allocate enough extra to allow structures to start at cache aligned
+ boundary. */
+ sc->status = malloc(sc->rxDescCount * rxStatusSize +
+ sc->txDescCount * txStatusSize +
+ cacheAlignment - 1, M_DEVBUF, M_NOWAIT);
+ sc->rx = malloc(sc->rxDescCount * sizeof(*sc->rx), M_DEVBUF, M_NOWAIT);
+ sc->tx = malloc(sc->txDescCount * sizeof(*sc->tx), M_DEVBUF, M_NOWAIT);
+ if (sc->status == NULL || sc->rx == NULL || sc->tx == NULL)
+ rtems_panic("No memory!\n");
+
+ /* Start status structures at cache aligned boundary. */
+ ptr = (char *) (((intptr_t) sc->status + cacheAlignment - 1) &
+ ~(cacheAlignment - 1));
+ memset(ptr, 0, sc->rxDescCount * rxStatusSize +
+ sc->txDescCount * txStatusSize);
+ memset(sc->rx, 0, sc->rxDescCount * sizeof(*sc->rx));
+ memset(sc->tx, 0, sc->txDescCount * sizeof(*sc->tx));
+ rtems_cache_flush_multiple_data_lines(ptr, sc->rxDescCount * rxStatusSize +
+ sc->txDescCount * txStatusSize);
+ for (i = 0; i < sc->rxDescCount; i++) {
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rx[i].m = m;
+ /* start dma at 32 bit boundary */
+ sc->rx[i].data.addr = (void *) (((intptr_t) m->m_data + 3) & ~3);
+ rtems_cache_invalidate_multiple_data_lines(
+ sc->rx[i].data.addr,
+ BFIN_ETHERNET_MAX_FRAME_LENGTH + 2);
+ sc->rx[i].data.dmaConfig = DMA_MODE_RX;
+ sc->rx[i].data.next = &(sc->rx[i].status);
+ sc->rx[i].status.addr = ptr;
+ if (i < sc->rxDescCount - 1) {
+ sc->rx[i].status.dmaConfig = DMA_MODE_STATUS;
+ sc->rx[i].status.next = &(sc->rx[i + 1].data);
+ } else {
+ sc->rx[i].status.dmaConfig = DMA_MODE_STATUS_LAST;
+ sc->rx[i].status.next = &(sc->rx[0].data);
+ }
+ ptr += rxStatusSize;
+ }
+ rtems_cache_flush_multiple_data_lines(sc->rx, sc->rxDescCount *
+ sizeof(*sc->rx));
+ for (i = 0; i < sc->txDescCount; i++) {
+ sc->tx[i].data.addr = &sc->tx[i].buffer.packet;
+ sc->tx[i].data.dmaConfig = DMA_MODE_TX;
+ sc->tx[i].data.next = &(sc->tx[i].status);
+ sc->tx[i].status.addr = ptr;
+ sc->tx[i].status.dmaConfig = DMA_MODE_STATUS_LAST;
+ if (i < sc->txDescCount - 1)
+ sc->tx[i].status.next = &(sc->tx[i + 1].data);
+ else
+ sc->tx[i].status.next = &(sc->tx[0].data);
+ sc->tx[i].inUse = false;
+ ptr += txStatusSize;
+ }
+ rtems_cache_flush_multiple_data_lines(sc->tx, sc->txDescCount *
+ sizeof(*sc->tx));
+
+ BFIN_REG32(rxdmaBase, DMA_NEXT_DESC_PTR_OFFSET) = (uint32_t) &sc->rx[0].data;
+ BFIN_REG32(txdmaBase, DMA_NEXT_DESC_PTR_OFFSET) = (uint32_t) &sc->tx[0].data;
+
+ hwaddr = sc->arpcom.ac_enaddr;
+ BFIN_REG16(ethBase, EMAC_ADDRHI_OFFSET) = ((uint16_t) hwaddr[5] << 8) |
+ hwaddr[4];
+ BFIN_REG32(ethBase, EMAC_ADDRLO_OFFSET) = ((uint32_t) hwaddr[3] << 24) |
+ ((uint32_t) hwaddr[2] << 16) |
+ ((uint32_t) hwaddr[1] << 8) |
+ hwaddr[0];
+
+ if (sc->acceptBroadcast)
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) &= ~EMAC_OPMODE_DBF;
+ else
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) |= EMAC_OPMODE_DBF;
+
+}
+
+/* send packet (caller provides header) */
+static void ethernetStart(struct ifnet *ifp) {
+ struct bfin_ethernetSoftc *sc;
+
+ sc = ifp->if_softc;
+
+ ifp->if_flags |= IFF_OACTIVE;
+ rtems_bsdnet_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
+}
+
+/* initialize and start the device */
+static void ethernetInit(void *arg) {
+ struct bfin_ethernetSoftc *sc;
+ struct ifnet *ifp;
+ void *ethBase;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+ ethBase = sc->ethBase;
+
+ if (sc->txDaemonTid == 0) {
+ initializeHardware(sc);
+
+ /* start driver tasks */
+ sc->rxDaemonTid = rtems_bsdnet_newproc("BFrx", 4096, rxDaemon, sc);
+ sc->txDaemonTid = rtems_bsdnet_newproc("BFtx", 4096, txDaemon, sc);
+
+ }
+
+ if (ifp->if_flags & IFF_PROMISC)
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) |= EMAC_OPMODE_PR;
+ else
+ BFIN_REG32(ethBase, EMAC_OPMODE_OFFSET) &= ~EMAC_OPMODE_PR;
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+}
+
+/* driver ioctl handler */
+static int ethernetIoctl(struct ifnet *ifp, ioctl_command_t command,
+ caddr_t data) {
+ int result;
+ struct bfin_ethernetSoftc *sc = ifp->if_softc;
+
+ result = 0;
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ ethernetStop(sc);
+ break;
+ case IFF_UP:
+ ethernetInit(sc);
+ break;
+ case IFF_UP | IFF_RUNNING:
+ ethernetStop(sc);
+ ethernetInit(sc);
+ break;
+ default:
+ break;
+ }
+ break;
+ case SIO_RTEMS_SHOW_STATS:
+ bfin_ethernetStats(sc);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ default:
+ result = EINVAL;
+ break;
+ }
+
+ return result;
+}
+
+/* attach a BFIN ETHERNET driver to the system */
+int bfin_ethernet_driver_attach(struct rtems_bsdnet_ifconfig *config,
+ int attaching,
+ bfin_ethernet_configuration_t *chip) {
+ struct bfin_ethernetSoftc *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+
+ if ((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
+ return 0;
+
+ if ((unitNumber <= 0) || (unitNumber > N_BFIN_ETHERNET)) {
+ printf("Bad bfin ethernet unit number %d.\n", unitNumber);
+ return 0;
+ }
+ sc = &ethernetSoftc[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf("Driver already in use.\n");
+ return 0;
+ }
+
+ memset(sc, 0, sizeof(*sc));
+
+ /* process options */
+ if (config->hardware_address)
+ memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ else
+ memset(sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxDescCount = config->rbuf_count;
+ else
+ sc->rxDescCount = chip->rxDescCount;
+ if (config->xbuf_count)
+ sc->txDescCount = config->xbuf_count;
+ else
+ sc->txDescCount = chip->txDescCount;
+ /* minimum two of each type descriptor */
+ if (sc->rxDescCount <= 1)
+ sc->rxDescCount = 2;
+ if (sc->txDescCount <= 1)
+ sc->txDescCount = 2;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ sc->sclk = chip->sclk;
+ sc->ethBase = chip->ethBaseAddress;
+ sc->rxdmaBase = chip->rxdmaBaseAddress;
+ sc->txdmaBase = chip->txdmaBaseAddress;
+
+ /* make sure we should not have any interrupts asserted */
+ resetHardware(sc);
+
+ sc->rmii = (chip->phyType == rmii);
+ sc->phyAddr = chip->phyAddr;
+
+ /* set up network interface values */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = ethernetInit;
+ ifp->if_ioctl = ethernetIoctl;
+ ifp->if_start = ethernetStart;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ return 1;
+}
+
diff --git a/bsps/bfin/shared/dev/clock.c b/bsps/bfin/shared/dev/clock.c
new file mode 100644
index 0000000000..d46ab3581e
--- /dev/null
+++ b/bsps/bfin/shared/dev/clock.c
@@ -0,0 +1,81 @@
+/* RTEMS Clock Tick Driver for Blackfin. Uses Blackfin Core Timer.
+ */
+
+/*
+ * Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <rtems/libio.h>
+#include <rtems/score/percpu.h>
+#include <bsp.h>
+#include <rtems/clockdrv.h>
+
+
+#include <libcpu/cecRegs.h>
+#include <libcpu/coreTimerRegs.h>
+
+#if (BFIN_ON_SKYEYE)
+#define CLOCK_DRIVER_USE_FAST_IDLE 1
+#endif
+
+volatile uint32_t Clock_driver_ticks;
+
+void Clock_exit(void);
+
+static rtems_isr clockISR(rtems_vector_number vector) {
+
+ Clock_driver_ticks += 1;
+
+#if CLOCK_DRIVER_USE_FAST_IDLE
+ do {
+ rtems_clock_tick();
+ } while ( _Thread_Heir == _Thread_Executing && _Thread_Executing->is_idle );
+#else
+ rtems_clock_tick();
+#endif
+}
+
+/*
+ * Clock_exit
+ *
+ * This routine allows the clock driver to exit by masking the interrupt and
+ * disabling the clock's counter.
+ */
+void Clock_exit(void)
+{
+ *(uint32_t volatile *) TCNTL = 0;
+}
+
+/*
+ * Clock_initialize
+ *
+ * This routine initializes the clock driver.
+ */
+rtems_device_driver Clock_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *pargp
+)
+{
+ Clock_driver_ticks = 0;
+
+ set_vector(clockISR, CEC_CORE_TIMER_VECTOR, 1);
+
+ *(uint32_t volatile *) TCNTL = TCNTL_TMPWR | TCNTL_TAUTORLD;
+ *(uint32_t volatile *) TSCALE = 0;
+ *(uint32_t volatile *) TPERIOD = CCLK / 1000000 *
+ rtems_configuration_get_microseconds_per_tick();
+ *(uint32_t volatile *) TCNTL = TCNTL_TMPWR | TCNTL_TAUTORLD | TCNTL_TMREN;
+
+ atexit(Clock_exit);
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/bfin/shared/dev/rtc.c b/bsps/bfin/shared/dev/rtc.c
new file mode 100644
index 0000000000..fa340a3c45
--- /dev/null
+++ b/bsps/bfin/shared/dev/rtc.c
@@ -0,0 +1,258 @@
+/*
+ * Real Time Clock Driver for Blackfin
+ */
+
+/*
+ * Copyright (c) 2006 by Atos Automacao Industrial Ltda.
+ * written by Alain Schaefer <alain.schaefer@easc.ch>
+ * and Antonio Giovanini <antonio@atos.com.br>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+
+#include <rtems.h>
+#include <rtems/tod.h>
+#include <rtems/rtc.h>
+#include <rtems/libio.h>
+#include <bsp.h>
+#include <libcpu/rtcRegs.h>
+#include <rtems/score/todimpl.h>
+
+/* The following are inside RTEMS -- we are violating visibility!!!
+ * Perhaps an API could be defined to get days since 1 Jan.
+ */
+extern const uint16_t _TOD_Days_to_date[2][13];
+
+/*
+ * Prototypes and routines used below
+ */
+int Leap_years_until_now (int year);
+
+void Init_RTC(void)
+{
+ *((uint16_t*)RTC_PREN) = RTC_PREN_PREN; /* Enable Prescaler */
+}
+
+/*
+ * Read time from RTEMS' clock manager and set it to RTC
+ */
+void setRealTimeFromRTEMS (void)
+{
+ rtems_time_of_day time_buffer;
+ rtems_status_code status;
+
+ status = rtems_clock_get_tod( &time_buffer );
+ if (status == RTEMS_SUCCESSFUL){
+ setRealTime(&time_buffer);
+ }
+}
+
+/*
+ * Read real time from RTC and set it to RTEMS' clock manager
+ */
+void setRealTimeToRTEMS (void)
+{
+ rtems_time_of_day time_buffer;
+
+ getRealTime(&time_buffer);
+ rtems_clock_set( &time_buffer );
+}
+
+/*
+ * Set the RTC time
+ */
+int setRealTime(
+ const rtems_time_of_day *tod
+)
+{
+ uint32_t days;
+ rtems_time_of_day tod_temp;
+
+ tod_temp = *tod;
+
+ days = (tod_temp.year - TOD_BASE_YEAR) * 365 + \
+ _TOD_Days_to_date[0][tod_temp.month] + tod_temp.day - 1;
+ if (tod_temp.month < 3)
+ days += Leap_years_until_now (tod_temp.year - 1);
+ else
+ days += Leap_years_until_now (tod_temp.year);
+
+ *((uint32_t volatile *)RTC_STAT) = (days << RTC_STAT_DAYS_SHIFT)|
+ (tod_temp.hour << RTC_STAT_HOURS_SHIFT)|
+ (tod_temp.minute << RTC_STAT_MINUTES_SHIFT)|
+ tod_temp.second;
+
+ return 0;
+}
+
+/*
+ * Get the time from the RTC.
+ */
+void getRealTime(
+ rtems_time_of_day *tod
+)
+{
+ uint32_t days, rtc_reg;
+ rtems_time_of_day tod_temp = { 0, 0, 0 };
+ int n, Leap_year;
+
+ rtc_reg = *((uint32_t volatile *)RTC_STAT);
+
+ days = (rtc_reg >> RTC_STAT_DAYS_SHIFT) + 1;
+
+ /* finding year */
+ tod_temp.year = days/365 + TOD_BASE_YEAR;
+ if (days%365 > Leap_years_until_now (tod_temp.year - 1)) {
+ days = (days%365) - Leap_years_until_now (tod_temp.year - 1);
+ } else {
+ tod_temp.year--;
+ days = (days%365) + 365 - Leap_years_until_now (tod_temp.year - 1);
+ }
+
+ /* finding month and day */
+ Leap_year = (((!(tod_temp.year%4)) && (tod_temp.year%100)) ||
+ (!(tod_temp.year%400)))?1:0;
+ for (n=1; n<=12; n++) {
+ if (days <= _TOD_Days_to_date[Leap_year][n+1]) {
+ tod_temp.month = n;
+ tod_temp.day = days - _TOD_Days_to_date[Leap_year][n];
+ break;
+ }
+ }
+
+ tod_temp.hour = (rtc_reg & RTC_STAT_HOURS_MASK) >> RTC_STAT_HOURS_SHIFT;
+ tod_temp.minute = (rtc_reg & RTC_STAT_MINUTES_MASK) >> RTC_STAT_MINUTES_SHIFT;
+ tod_temp.second = (rtc_reg & RTC_STAT_SECONDS_MASK);
+ tod_temp.ticks = 0;
+ *tod = tod_temp;
+}
+
+/*
+ * Return the difference between RTC and RTEMS' clock manager time in minutes.
+ * If the difference is greater than 1 day, this returns 9999.
+ */
+int checkRealTime (void)
+{
+ rtems_time_of_day rtems_tod;
+ rtems_time_of_day rtc_tod;
+ uint32_t rtems_time;
+ uint32_t rtc_time;
+
+ (void) rtems_clock_get_tod( &rtems_tod );
+ getRealTime ( &rtc_tod );
+
+ rtems_time = _TOD_To_seconds( &rtems_tod );
+ rtc_time = _TOD_To_seconds( &rtc_tod );
+
+ return rtems_time - rtc_time;
+}
+
+int Leap_years_until_now (int year)
+{
+ return ((year/4 - year/100 + year/400) -
+ ((TOD_BASE_YEAR - 1)/4 - (TOD_BASE_YEAR - 1)/100 +
+ (TOD_BASE_YEAR - 1)/400));
+}
+
+rtems_device_driver rtc_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor_arg,
+ void *arg
+)
+{
+ rtems_status_code status;
+
+ /*
+ * Register and initialize the primary RTC's
+ */
+
+ status = rtems_io_register_name( RTC_DEVICE_NAME, major, 0 );
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+
+ Init_RTC();
+
+ setRealTimeToRTEMS();
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver rtc_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_libio_rw_args_t *rw = arg;
+ rtems_time_of_day *tod = (rtems_time_of_day *) rw->buffer;
+
+ rw->offset = 0;
+ rw->bytes_moved = 0;
+
+ if (rw->count != sizeof( rtems_time_of_day)) {
+ return RTEMS_INVALID_SIZE;
+ }
+
+ getRealTime( tod);
+
+ rw->bytes_moved = rw->count;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver rtc_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ int rv = 0;
+ rtems_libio_rw_args_t *rw = arg;
+ const rtems_time_of_day *tod = (const rtems_time_of_day *) rw->buffer;
+
+ rw->offset = 0;
+ rw->bytes_moved = 0;
+
+ if (rw->count != sizeof( rtems_time_of_day)) {
+ return RTEMS_INVALID_SIZE;
+ }
+
+ rv = setRealTime( tod);
+ if (rv != 0) {
+ return RTEMS_IO_ERROR;
+ }
+
+ rw->bytes_moved = rw->count;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver rtc_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver rtc_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver rtc_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ return RTEMS_NOT_IMPLEMENTED;
+}
diff --git a/bsps/bfin/shared/dev/spi.c b/bsps/bfin/shared/dev/spi.c
new file mode 100644
index 0000000000..e1024e8d10
--- /dev/null
+++ b/bsps/bfin/shared/dev/spi.c
@@ -0,0 +1,240 @@
+/* SPI driver for Blackfin
+ *
+ * Copyright (c) 2010 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <bsp.h>
+#include <rtems/error.h>
+#include <rtems/bspIo.h>
+#include <errno.h>
+#include <rtems/libi2c.h>
+#include <libcpu/spiRegs.h>
+#include <libcpu/spi.h>
+
+
+#ifndef BFIN_REG16
+#define BFIN_REG16(base, offset) \
+ (*((uint16_t volatile *) ((uint8_t *)(base) + (offset))))
+#endif
+
+
+static bfin_spi_state_t *bfin_spi;
+
+
+void bfin_spi_isr(int v) {
+ bfin_spi_state_t *state;
+ uint16_t r;
+
+ state = bfin_spi;
+ if (state->len > state->bytes_per_word) {
+ if (state->wr_ptr) {
+ if (state->bytes_per_word == 2)
+ r = *(uint16_t *) state->wr_ptr;
+ else
+ r = (uint16_t) *state->wr_ptr;
+ state->wr_ptr += state->bytes_per_word;
+ } else
+ r = state->idle_pattern;
+ BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r;
+ }
+ state->len -= state->bytes_per_word;
+ if (state->len <= 0) {
+ /*
+ The transfers are done, so I don't want to kick off another
+ transfer or get any more interrupts. Reading the last word from
+ SPI_SHADOW instead of SPI_RDBR should prevent it from triggering
+ another transfer, but that doesn't clear the interrupt flag. I
+ could mask the interrupt in the SIC, but that would preclude ever
+ using the DMA channel that shares the interrupt independently (and
+ they might just share it with something more important in some other
+ member of the Blackfin family). And who knows what problems it
+ might cause in this code potentially dealing with that still pended
+ interrupt at the beginning of the next transfer.
+
+ So instead I disable the SPI interface, read the data from RDBR
+ (thus clearing the interrupt but not triggering another transfer
+ since the interface is disabled), then re-eanble the interface.
+ This has the problem that the bf537 tri-states the SPI signals
+ while the interface is disabled. Either adding pull-ups on at
+ least the chip select signals, or using GPIOs for them so they're
+ not controlled by the SPI module, would be correct fixes for that
+ (really pull-ups/downs should be added to the SPI CLK and MOSI
+ signals as well to insure they cannot float into some region that
+ causes input structures to consume excessive power). Or they can
+ all be left alone, assuming that there's enough capacitance on the
+ lines to prevent any problems for the short time they're being left
+ disabled.
+
+ An alternative approach I attempted involved switching TIMOD
+ between RDBR and TDBR when starting and finishing a transfer, but
+ I didn't get anywhere with that. In my limited testing TIMOD TDBR
+ wasn't behaving as I expected it to, but maybe with more
+ experimentation I'd find some solution there. However I'm out
+ of time for this project, at least for now.
+ */
+
+ BFIN_REG16(state->base, SPI_CTL_OFFSET) &= ~SPI_CTL_SPE;
+ r = BFIN_REG16(state->base, SPI_RDBR_OFFSET);
+ BFIN_REG16(state->base, SPI_CTL_OFFSET) |= SPI_CTL_SPE;
+ rtems_semaphore_release(state->sem);
+ } else
+ r = BFIN_REG16(state->base, SPI_RDBR_OFFSET);
+
+ if (state->rd_ptr) {
+ if (state->bytes_per_word == 2)
+ *(uint16_t *) state->rd_ptr = r;
+ else
+ *state->rd_ptr = (uint8_t) r;
+ state->rd_ptr += state->bytes_per_word;
+ }
+}
+
+static rtems_status_code setTFRMode(rtems_libi2c_bus_t *bus,
+ const rtems_libi2c_tfr_mode_t *tfrMode) {
+ rtems_status_code result;
+ bfin_spi_state_t *state;
+ uint32_t divisor;
+ uint16_t ctrl;
+
+ result = RTEMS_SUCCESSFUL;
+ state = &((bfin_spi_bus_t *) bus)->p;
+
+ if (result == RTEMS_SUCCESSFUL) {
+ if (tfrMode->bits_per_char != 8 &&
+ tfrMode->bits_per_char != 16)
+ result = RTEMS_INVALID_NUMBER;
+ if (tfrMode->baudrate <= 0)
+ result = RTEMS_INVALID_NUMBER;
+ }
+ if (result == RTEMS_SUCCESSFUL) {
+ divisor = (SCLK / 2 + tfrMode->baudrate - 1) /
+ tfrMode->baudrate;
+ if (divisor < 2)
+ divisor = 2;
+ else if (divisor > 65535)
+ result = RTEMS_INVALID_NUMBER;
+ }
+ if (result == RTEMS_SUCCESSFUL) {
+ state->idle_pattern = (uint16_t) tfrMode->idle_char;
+ state->bytes_per_word = (tfrMode->bits_per_char > 8) ? 2 : 1;
+ BFIN_REG16(state->base, SPI_BAUD_OFFSET) = divisor;
+ ctrl = BFIN_REG16(state->base, SPI_CTL_OFFSET);
+ if (tfrMode->lsb_first)
+ ctrl |= SPI_CTL_LSBF;
+ else
+ ctrl &= ~SPI_CTL_LSBF;
+ if (tfrMode->bits_per_char > 8)
+ ctrl |= SPI_CTL_SIZE;
+ else
+ ctrl &= ~SPI_CTL_SIZE;
+ if (tfrMode->clock_inv)
+ ctrl |= SPI_CTL_CPOL;
+ else
+ ctrl &= ~SPI_CTL_CPOL;
+ if (tfrMode->clock_phs)
+ ctrl |= SPI_CTL_CPHA;
+ else
+ ctrl &= ~SPI_CTL_CPHA;
+ BFIN_REG16(state->base, SPI_CTL_OFFSET) = ctrl;
+ }
+
+ return result;
+}
+
+static int readWrite(rtems_libi2c_bus_t *bus, uint8_t *rdBuf,
+ const uint8_t *wrBuf, int len) {
+ rtems_status_code result;
+ bfin_spi_state_t *state;
+ uint16_t r;
+
+ result = RTEMS_SUCCESSFUL;
+ state = &((bfin_spi_bus_t *) bus)->p;
+
+ if (len) {
+ state->rd_ptr = rdBuf;
+ state->wr_ptr = wrBuf;
+ state->len = len;
+ if (state->wr_ptr) {
+ if (state->bytes_per_word == 2)
+ r = *(uint16_t *) state->wr_ptr;
+ else
+ r = (uint16_t) *state->wr_ptr;
+ state->wr_ptr += state->bytes_per_word;
+ } else
+ r = state->idle_pattern;
+ BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r;
+ BFIN_REG16(state->base, SPI_RDBR_OFFSET); /* trigger */
+ /* wait until done */
+ do {
+ result = rtems_semaphore_obtain(state->sem, RTEMS_WAIT, 100);
+ } while (result == RTEMS_SUCCESSFUL && state->len > 0);
+ }
+
+ return (result == RTEMS_SUCCESSFUL) ? len : -result;
+}
+
+
+rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus) {
+ rtems_status_code result;
+ bfin_spi_state_t *state;
+
+ state = &((bfin_spi_bus_t *) bus)->p;
+
+ BFIN_REG16(state->base, SPI_CTL_OFFSET) = SPI_CTL_SPE |
+ SPI_CTL_MSTR |
+ SPI_CTL_CPHA |
+ SPI_CTL_TIMOD_RDBR;
+
+ result = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
+ 0,
+ RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &state->sem);
+ if (result == RTEMS_SUCCESSFUL)
+ bfin_spi = state; /* for isr */
+
+ return result;
+}
+
+rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus) {
+
+ return RTEMS_SUCCESSFUL;
+}
+
+int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) {
+
+ return readWrite(bus, buf, NULL, len);
+}
+
+int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) {
+
+ return readWrite(bus, NULL, buf, len);
+}
+
+int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) {
+ int result;
+
+ result = -RTEMS_NOT_DEFINED;
+ switch(cmd) {
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+ result = -setTFRMode(bus, (const rtems_libi2c_tfr_mode_t *) arg);
+ break;
+ case RTEMS_LIBI2C_IOCTL_READ_WRITE:
+ result = readWrite(bus,
+ ((rtems_libi2c_read_write_t *) arg)->rd_buf,
+ ((rtems_libi2c_read_write_t *) arg)->wr_buf,
+ ((rtems_libi2c_read_write_t *) arg)->byte_cnt);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
diff --git a/bsps/bfin/shared/dev/sport.c b/bsps/bfin/shared/dev/sport.c
new file mode 100644
index 0000000000..6ed481b593
--- /dev/null
+++ b/bsps/bfin/shared/dev/sport.c
@@ -0,0 +1,2 @@
+/* placeholder */
+
diff --git a/bsps/bfin/shared/dev/timer.c b/bsps/bfin/shared/dev/timer.c
new file mode 100644
index 0000000000..02540fe2ce
--- /dev/null
+++ b/bsps/bfin/shared/dev/timer.c
@@ -0,0 +1,96 @@
+/**
+ * @file
+ * @brief Timer for Blackfin
+ *
+ * This file manages the benchmark timer used by the RTEMS Timing Test
+ * Suite. Each measured time period is demarcated by calls to
+ * benchmark_timer_initialize() and benchmark_timer_read().
+ * benchmark_timer_read() usually returns the number of microseconds
+ * since benchmark_timer_initialize() exitted.
+ */
+
+/*
+ * Copyright (c) 2006 by Atos Automacao Industrial Ltda.
+ * written by Alain Schaefer <alain.schaefer@easc.ch>
+ * and Antonio Giovanini <antonio@atos.com.br>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+uint32_t Timer_interrupts;
+bool benchmark_timer_find_average_overhead;
+
+/*
+ * benchmark_timer_initialize
+ *
+ * Blackfin processor has a counter for clock cycles.
+ */
+void benchmark_timer_initialize( void )
+{
+
+ /*reset counters*/
+ __asm__ ("R2 = 0;");
+ __asm__ ("CYCLES = R2;");
+ __asm__ ("CYCLES2 = R2;");
+ /*start counters*/
+ __asm__ ("R2 = SYSCFG;");
+ __asm__ ("BITSET(R2,1);");
+ __asm__ ("SYSCFG = R2");
+
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t clicks;
+ uint32_t total;
+ register uint32_t cycles __asm__ ("R2");
+
+ /* stop counter */
+ __asm__ ("R2 = SYSCFG;");
+ __asm__ ("BITCLR(R2,1);");
+ __asm__ ("SYSCFG = R2;");
+ __asm__ ("R2 = CYCLES;");
+
+
+ clicks = cycles; /* Clock cycles */
+
+ /* converting to microseconds */
+ total = clicks / (CCLK/1000000);
+
+ if ( benchmark_timer_find_average_overhead == 1 )
+ return total; /* in XXX microsecond units */
+ else {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/bfin/shared/dev/twi.c b/bsps/bfin/shared/dev/twi.c
new file mode 100644
index 0000000000..0d6e6ca0b1
--- /dev/null
+++ b/bsps/bfin/shared/dev/twi.c
@@ -0,0 +1,253 @@
+/* this is not much more than a shell; it does not do anything useful yet */
+
+/* TWI (I2C) driver for Blackfin
+ *
+ * Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <libcpu/twiRegs.h>
+#include <libcpu/twi.h>
+
+
+#ifndef N_BFIN_TWI
+#define N_BFIN_TWI 1
+#endif
+
+#define BFIN_REG16(base, offset) \
+ (*((uint16_t volatile *) ((char *)(base) + (offset))))
+
+
+static struct {
+ void *base;
+ rtems_id irqSem;
+ rtems_id mutex;
+ bfin_twi_callback_t callback;
+ void *callbackArg;
+ bfin_twi_request_t volatile *req;
+ uint8_t volatile *dataPtr;
+ int volatile count;
+ bool volatile masterActive;
+ rtems_status_code volatile masterResult;
+ bool volatile slaveActive;
+} twi[N_BFIN_TWI];
+
+
+rtems_status_code bfin_twi_init(int channel, bfin_twi_config_t *config) {
+ rtems_status_code result;
+ void *base;
+
+ if (channel < 0 || channel >= N_BFIN_TWI)
+ return RTEMS_INVALID_NUMBER;
+
+ base = config->base;
+ twi[channel].base = base;
+
+ result = rtems_semaphore_create(rtems_build_name('t','w','i','s'),
+ 0,
+ RTEMS_FIFO |
+ RTEMS_SIMPLE_BINARY_SEMAPHORE |
+ RTEMS_NO_INHERIT_PRIORITY |
+ RTEMS_NO_PRIORITY_CEILING |
+ RTEMS_LOCAL,
+ 0,
+ &twi[channel].irqSem);
+ result = rtems_semaphore_create(rtems_build_name('t','w','i','m'),
+ 1,
+ RTEMS_PRIORITY |
+ RTEMS_SIMPLE_BINARY_SEMAPHORE |
+ RTEMS_INHERIT_PRIORITY |
+ RTEMS_NO_PRIORITY_CEILING |
+ RTEMS_LOCAL,
+ 0,
+ &twi[channel].mutex);
+ BFIN_REG16(base, TWI_CONTROL_OFFSET) =
+ (uint16_t) (((config->sclk +9999999) / 10000000) <<
+ TWI_CONTROL_PRESCALE_SHIFT) |
+ TWI_CONTROL_TWI_ENA;
+ BFIN_REG16(base, TWI_CLKDIV_OFFSET) = config->fast ?
+ ((8 << TWI_CLKDIV_CLKHI_SHIFT) |
+ (17 << TWI_CLKDIV_CLKLOW_SHIFT)) :
+ ((33 << TWI_CLKDIV_CLKHI_SHIFT) |
+ (67 << TWI_CLKDIV_CLKLOW_SHIFT));
+ BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = 0;
+ BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = config->fast ?
+ TWI_MASTER_CTL_FAST :
+ 0;
+ BFIN_REG16(base, TWI_SLAVE_ADDR_OFFSET) = (uint16_t) config->slave_address <<
+ TWI_SLAVE_ADDR_SADDR_SHIFT;
+ BFIN_REG16(base, TWI_MASTER_STAT_OFFSET) = TWI_MASTER_STAT_BUFWRERR |
+ TWI_MASTER_STAT_BUFRDERR |
+ TWI_MASTER_STAT_DNAK |
+ TWI_MASTER_STAT_ANAK |
+ TWI_MASTER_STAT_LOSTARB;
+ BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = TWI_FIFO_CTL_XMTFLUSH |
+ TWI_FIFO_CTL_RCVFLUSH;
+ BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = 0;
+ BFIN_REG16(base, TWI_INT_STAT_OFFSET) = TWI_INT_STAT_RCVSERV |
+ TWI_INT_STAT_XMTSERV |
+ TWI_INT_STAT_MERR |
+ TWI_INT_STAT_MCOMP |
+ TWI_INT_STAT_SOVF |
+ TWI_INT_STAT_SERR |
+ TWI_INT_STAT_SCOMP |
+ TWI_INT_STAT_SINIT;
+ BFIN_REG16(base, TWI_INT_MASK_OFFSET) = TWI_INT_MASK_RCVSERVM |
+ TWI_INT_MASK_XMTSERVM;
+
+ return result;
+}
+
+rtems_status_code bfin_twi_register_callback(int channel,
+ bfin_twi_callback_t callback,
+ void *arg) {
+ void *base;
+ int level;
+
+ if (channel < 0 || channel >= N_BFIN_TWI)
+ return RTEMS_INVALID_NUMBER;
+
+ base = twi[channel].base;
+ if (callback == NULL)
+ BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = 0;
+ rtems_interrupt_disable(level);
+ twi[channel].callback = callback;
+ twi[channel].callbackArg = arg;
+ rtems_interrupt_enable(level);
+ if (callback != NULL)
+ BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = TWI_SLAVE_CTL_GEN |
+ TWI_SLAVE_CTL_SEN;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+void bfin_twi_isr(int source) {
+ void *base;
+ int i;
+ uint16_t r;
+ uint16_t stat;
+
+ for (i = 0; i < N_BFIN_TWI; i++) {
+ base = twi[i].base;
+ if (base) {
+ stat = BFIN_REG16(base, TWI_INT_STAT_OFFSET);
+ if (stat) {
+ BFIN_REG16(base, TWI_INT_STAT_OFFSET) = stat;
+ if ((stat & TWI_INT_STAT_SINIT) && !twi[i].slaveActive) {
+ twi[i].slaveActive = true;
+ r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
+ BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
+ BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
+ r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
+ BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r | TWI_SLAVE_CTL_STDVAL;
+ }
+ if (twi[i].slaveActive) {
+
+
+ if (stat & (TWI_INT_STAT_SCOMP | TWI_INT_STAT_SERR)) {
+
+
+ r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
+ BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r & ~TWI_SLAVE_CTL_STDVAL;
+ twi[i].slaveActive = false;
+
+
+ }
+ }
+ if (twi[i].masterActive && !twi[i].slaveActive) {
+
+
+ if (stat & (TWI_INT_STAT_MCOMP | TWI_INT_STAT_MERR)) {
+ if (!(stat & TWI_INT_STAT_MERR)) {
+
+
+ rtems_semaphore_release(twi[i].irqSem);
+
+
+ } else
+ rtems_semaphore_release(twi[i].irqSem);
+ }
+ }
+ }
+ }
+ }
+}
+
+rtems_status_code bfin_twi_request(int channel, uint8_t address,
+ bfin_twi_request_t *request,
+ rtems_interval timeout) {
+ rtems_status_code result;
+ void *base;
+ rtems_interrupt_level level;
+ uint16_t r;
+ uint16_t masterMode;
+
+ if (channel < 0 || channel >= N_BFIN_TWI)
+ return RTEMS_INVALID_NUMBER;
+ result = rtems_semaphore_obtain(twi[channel].mutex,
+ RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if (result == RTEMS_SUCCESSFUL) {
+ base = twi[channel].base;
+ twi[channel].req = request;
+
+ if (request->write) {
+ twi[channel].dataPtr = request->data;
+ twi[channel].count = request->count;
+ } else
+ twi[channel].count = 0;
+
+ BFIN_REG16(base, TWI_MASTER_ADDR_OFFSET) = (uint16_t) address <<
+ TWI_MASTER_ADDR_MADDR_SHIFT;
+ masterMode = BFIN_REG16(base, TWI_MASTER_CTL_OFFSET);
+ masterMode |= (request->count << TWI_MASTER_CTL_DCNT_SHIFT);
+ if (request->next)
+ masterMode |= TWI_MASTER_CTL_RSTART;
+ if (!request->write)
+ masterMode |= TWI_MASTER_CTL_MDIR;
+ masterMode |= TWI_MASTER_CTL_MEN;
+ rtems_interrupt_disable(level);
+ if (!twi[channel].slaveActive) {
+ r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
+ BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
+ BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
+ if (request->write) {
+ while (twi[channel].count &&
+ (BFIN_REG16(base, TWI_FIFO_STAT_OFFSET) &
+ TWI_FIFO_STAT_XMTSTAT_MASK) !=
+ TWI_FIFO_STAT_XMTSTAT_FULL) {
+ BFIN_REG16(base, TWI_XMT_DATA8_OFFSET) =
+ (uint16_t) *twi[channel].dataPtr++;
+ twi[channel].count--;
+ }
+ }
+ twi[channel].masterActive = true;
+ BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = masterMode;
+ } else {
+ twi[channel].masterActive = false;
+ twi[channel].masterResult = -1; /* BISON (code should be equiv to lost arbitration) */
+ }
+ rtems_interrupt_enable(level);
+ while (result == RTEMS_SUCCESSFUL && twi[channel].masterActive)
+ result = rtems_semaphore_obtain(twi[channel].irqSem,
+ RTEMS_WAIT, timeout);
+ if (result == RTEMS_SUCCESSFUL)
+ result = twi[channel].masterResult;
+ else {
+ /* BISON abort */
+
+
+
+ }
+ rtems_semaphore_release(twi[channel].mutex);
+ }
+ return result;
+}
+
diff --git a/bsps/bfin/shared/dev/uart.c b/bsps/bfin/shared/dev/uart.c
new file mode 100644
index 0000000000..18a522e121
--- /dev/null
+++ b/bsps/bfin/shared/dev/uart.c
@@ -0,0 +1,528 @@
+/* UART driver for Blackfin
+ */
+
+/*
+ * Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <termios.h>
+#include <stdlib.h>
+
+#include <libcpu/uartRegs.h>
+#include <libcpu/dmaRegs.h>
+#include <libcpu/uart.h>
+
+/* flags */
+#define BFIN_UART_XMIT_BUSY 0x01
+
+static bfin_uart_config_t *uartsConfig;
+
+static int pollRead(int minor)
+{
+ int c;
+ uint32_t base;
+
+ 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].uart_useInterrupts &&
+ *((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_DR)
+ c = *((uint16_t volatile *) (base + UART_RBR_OFFSET));
+ else
+ c = -1;
+
+ return c;
+}
+
+char bfin_uart_poll_read(rtems_device_minor_number minor)
+{
+ int c;
+
+ do {
+ c = pollRead(minor);
+ } while (c == -1);
+
+ return c;
+}
+
+void bfin_uart_poll_write(int minor, char c)
+{
+ uint32_t base;
+
+ base = uartsConfig->channels[minor].uart_baseAddress;
+
+ while (!(*((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_THRE))
+ ;
+ *(uint16_t volatile *) (base + UART_THR_OFFSET) = c;
+}
+
+/*
+ * Console Termios Support Entry Points
+ *
+ */
+
+static ssize_t pollWrite(int minor, const char *buf, size_t len)
+{
+ size_t count;
+ for ( count = 0; count < len; count++ )
+ bfin_uart_poll_write(minor, *buf++);
+
+ return count;
+}
+
+/**
+ * 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;
+
+ 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;
+ */
+
+
+ *(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));
+ }
+
+ *(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;
+
+ /**
+ * 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 :(
+ */
+ }
+}
+
+
+/**
+ * Set the UART attributes.
+ * @param minor
+ * @param termios
+ * @return
+ */
+static int setAttributes(int minor, const struct termios *termios)
+{
+ uint32_t base;
+ int baud;
+ uint16_t divisor;
+ uint16_t lcr;
+
+ base = uartsConfig->channels[minor].uart_baseAddress;
+ switch (termios->c_ospeed) {
+ case B0: baud = 0; break;
+ case B50: baud = 50; break;
+ case B75: baud = 75; break;
+ case B110: baud = 110; break;
+ case B134: baud = 134; break;
+ case B150: baud = 150; break;
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ default: baud = -1; break;
+ }
+ 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; break;
+ case CS6: lcr = UART_LCR_WLS_6; break;
+ case CS7: lcr = UART_LCR_WLS_7; break;
+ default:
+ case CS8: lcr = UART_LCR_WLS_8; break;
+ }
+ switch (termios->c_cflag & (PARENB | PARODD)) {
+ case PARENB:
+ lcr |= UART_LCR_PEN | UART_LCR_EPS;
+ break;
+ case PARENB | PARODD:
+ lcr |= UART_LCR_PEN;
+ break;
+ default:
+ break;
+ }
+ if (termios->c_cflag & CSTOPB)
+ lcr |= UART_LCR_STB;
+
+ if (baud > 0) {
+ divisor = (uint16_t) (uartsConfig->freq / (baud * 16));
+ *(uint16_t volatile *) (base + UART_LCR_OFFSET) = lcr | 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) = lcr;
+
+ return 0;
+}
+
+/**
+ * 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;
+
+ /**
+ * Sanity Check
+ */
+ if (
+ NULL == buf || NULL == channel || NULL == uartsConfig
+ || minor < 0 || 0 == len
+ ) {
+ return 0;
+ }
+
+ channel = &(uartsConfig->channels[minor]);
+
+ if ( NULL == channel || channel->flags & BFIN_UART_XMIT_BUSY ) {
+ return 0;
+ }
+
+ 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;
+
+ return 0;
+}
+
+/**
+ * This function implements RX ISR
+ */
+void bfinUart_rxIsr(void *_arg)
+{
+ /**
+ * TODO: UART RX ISR implementation.
+ */
+}
+
+/**
+ * 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;
+ }
+
+ 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);
+}
+
+/**
+ * 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;
+
+ /**
+ * Sanity Check
+ */
+ if ( NULL == buf || 0 > minor || NULL == uartsConfig || 0 == len ) {
+ return 0;
+ }
+
+ channel = &(uartsConfig->channels[minor]);
+
+ /**
+ * Sanity Check and check for transmit busy.
+ */
+ if ( NULL == channel || BFIN_UART_XMIT_BUSY & channel->flags ) {
+ return 0;
+ }
+
+ 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;
+
+ 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.
+ */
+ }
+}
+
+/**
+ * Function called during exit
+ */
+static 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_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 */
+ };
+
+ /**
+ * 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 */
+ pollRead, /* pollRead */
+ uart_interruptWrite, /* write */
+ setAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
+ };
+
+ /**
+ * 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);
+ }
+
+ args = arg;
+ uartsConfig->channels[minor].termios = args->iop->data1;
+
+ 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/bsps/bfin/shared/interrupt.c b/bsps/bfin/shared/interrupt.c
new file mode 100644
index 0000000000..7fe1eb19f7
--- /dev/null
+++ b/bsps/bfin/shared/interrupt.c
@@ -0,0 +1,196 @@
+/* Support for Blackfin interrupt controller
+ *
+ * Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+#include <bsp.h>
+#include <libcpu/cecRegs.h>
+#include <libcpu/sicRegs.h>
+#include <string.h>
+#include <libcpu/interrupt.h>
+
+
+static struct {
+ uint32_t mask;
+ bfin_isr_t *head;
+} vectors[CEC_INTERRUPT_COUNT];
+
+static uint32_t globalMask;
+
+
+static rtems_isr interruptHandler(rtems_vector_number vector) {
+ bfin_isr_t *isr;
+ uint32_t sourceMask;
+
+ vector -= CEC_INTERRUPT_BASE_VECTOR;
+ if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
+ isr = vectors[vector].head;
+ sourceMask = *(uint32_t volatile *) SIC_ISR &
+ *(uint32_t volatile *) SIC_IMASK;
+ while (isr) {
+ if (sourceMask & isr->mask) {
+ isr->isr(isr->source);
+ sourceMask = *(uint32_t volatile *) SIC_ISR &
+ *(uint32_t volatile *) SIC_IMASK;
+ }
+ isr = isr->next;
+ }
+ }
+}
+
+void bfin_interrupt_init(void) {
+ int source;
+ int vector;
+ uint32_t r;
+ int i;
+ int j;
+
+ globalMask = ~(uint32_t) 0;
+ *(uint32_t volatile *) SIC_IMASK = 0;
+ memset(vectors, 0, sizeof(vectors));
+ /* build mask showing what SIC sources drive each CEC vector */
+ source = 0;
+ for (i = 0; i < SIC_IAR_COUNT; i++) {
+ r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS + i * SIC_IAR_PITCH);
+ for (j = 0; j < 8; j++) {
+ vector = r & 0x0f;
+ if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
+ if (vectors[vector].mask == 0)
+ /* install our local handler */
+ set_vector(interruptHandler, vector + CEC_INTERRUPT_BASE_VECTOR, 1);
+ vectors[vector].mask |= (1 << source);
+ }
+ r >>= 4;
+ source++;
+ }
+ }
+}
+
+/* modify SIC_IMASK based on ISR list for a particular CEC vector */
+static void setMask(int vector) {
+ bfin_isr_t *isr;
+ uint32_t mask;
+ uint32_t r;
+
+ mask = 0;
+ isr = vectors[vector].head;
+ while (isr) {
+ mask |= isr->mask;
+ isr = isr->next;
+ }
+ r = *(uint32_t volatile *) SIC_IMASK;
+ r &= ~vectors[vector].mask;
+ r |= mask;
+ r &= globalMask;
+ *(uint32_t volatile *) SIC_IMASK = r;
+}
+
+/* add an ISR to the list for whichever vector it belongs to */
+void 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].mask & (1 << isr->source))
+ break;
+ if (isr->vector < CEC_INTERRUPT_COUNT) {
+ isr->next = NULL;
+ isr->mask = 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;
+}
+
+void 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);
+}
+
+void bfin_interrupt_enable(bfin_isr_t *isr, bool enable) {
+ rtems_interrupt_level isrLevel;
+
+ rtems_interrupt_disable(isrLevel);
+ isr->mask = enable ? (1 << isr->source) : 0;
+ 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].mask & (1 << source))
+ break;
+ if (vector < CEC_INTERRUPT_COUNT) {
+ rtems_interrupt_disable(isrLevel);
+ walk = vectors[vector].head;
+ while (walk) {
+ walk->mask = enable ? (1 << source) : 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].mask & (1 << source))
+ break;
+ if (vector < CEC_INTERRUPT_COUNT) {
+ rtems_interrupt_disable(isrLevel);
+ if (enable)
+ globalMask |= 1 << source;
+ else
+ globalMask &= ~(1 << source);
+ setMask(vector);
+ rtems_interrupt_enable(isrLevel);
+ }
+}
+
diff --git a/bsps/bfin/shared/mmu.c b/bsps/bfin/shared/mmu.c
new file mode 100644
index 0000000000..bf3311b5b4
--- /dev/null
+++ b/bsps/bfin/shared/mmu.c
@@ -0,0 +1,44 @@
+/* Blackfin MMU Support
+ *
+ * Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
+ * written by Allan Hessenflow <allanh@kallisti.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+
+#include <rtems.h>
+
+#include <libcpu/memoryRegs.h>
+#include <libcpu/mmu.h>
+
+/* NOTE: see notes in mmu.h */
+
+void bfin_mmu_init(bfin_mmu_config_t *config) {
+ intptr_t addr;
+ intptr_t data;
+ int i;
+
+ addr = (intptr_t) ICPLB_ADDR0;
+ data = (intptr_t) ICPLB_DATA0;
+ for (i = 0; i < sizeof(config->instruction) / sizeof(config->instruction[0]);
+ i++) {
+ *(uint32_t volatile *) addr = (uint32_t) config->instruction[i].address;
+ addr += ICPLB_ADDR_PITCH;
+ *(uint32_t volatile *) data = config->instruction[i].flags;
+ data += ICPLB_DATA_PITCH;
+ }
+ *(uint32_t volatile *) IMEM_CONTROL |= IMEM_CONTROL_ENICPLB;
+ addr = (intptr_t) DCPLB_ADDR0;
+ data = (intptr_t) DCPLB_DATA0;
+ for (i = 0; i < sizeof(config->data) / sizeof(config->data[0]); i++) {
+ *(uint32_t volatile *) addr = (uint32_t) config->data[i].address;
+ addr += DCPLB_ADDR_PITCH;
+ *(uint32_t volatile *) data = config->data[i].flags;
+ data += DCPLB_DATA_PITCH;
+ }
+ *(uint32_t volatile *) DMEM_CONTROL |= DMEM_CONTROL_ENDCPLB;
+}
+
diff --git a/bsps/bfin/shared/shared.am b/bsps/bfin/shared/shared.am
new file mode 100644
index 0000000000..93009c3d16
--- /dev/null
+++ b/bsps/bfin/shared/shared.am
@@ -0,0 +1,8 @@
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/mmu.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/clock.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/rtc.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/spi.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/sport.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/timer.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/twi.c
+libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/dev/uart.c