bsp/bfin: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.
This commit is contained in:
Sebastian Huber
2018-03-21 16:38:43 +01:00
parent 96400050ed
commit e2bd1f653a
21 changed files with 15 additions and 157 deletions

View File

@@ -30,15 +30,10 @@ libbsp_a_SOURCES += ../../shared/bspreset.c
libbsp_a_SOURCES += console/console.c
libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/cache/cache.c
libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/mmu.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/interrupt.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/uart.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/clock.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/rtc.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/timer.rel
libbsp_a_SOURCES += ../../../../../../bsps/bfin/TLL6527M/start/interrupt.c
EXTRA_DIST += times
include $(top_srcdir)/../../../../automake/local.am
include $(srcdir)/../../../../../../bsps/bfin/shared/shared.am
include $(srcdir)/../../../../../../bsps/bfin/TLL6527M/headers.am

View File

@@ -5,7 +5,6 @@
include $(RTEMS_ROOT)/make/custom/default.cfg
RTEMS_CPU=bfin
RTEMS_CPU_MODEL=bf52x
# This contains the compiler options necessary to select the CPU model
# and (hopefully) optimize for it.

View File

@@ -31,21 +31,13 @@ libbsp_a_SOURCES += ../../shared/bspreset.c
libbsp_a_SOURCES += console/console.c
libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/cache/cache.c
libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/interrupt.c
if HAS_NETWORKING
libbsp_a_SOURCES += network/networkconfig.c
endif
libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/mmu.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/interrupt.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/uart.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/clock.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/rtc.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/timer.rel
if HAS_NETWORKING
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/network.rel
libbsp_a_SOURCES += ../../../../../../bsps/bfin/bf537Stamp/net/ethernet.c
endif
include $(top_srcdir)/../../../../automake/local.am
include $(srcdir)/../../../../../../bsps/bfin/shared/shared.am
include $(srcdir)/../../../../../../bsps/bfin/bf537Stamp/headers.am

View File

@@ -5,7 +5,6 @@
include $(RTEMS_ROOT)/make/custom/default.cfg
RTEMS_CPU=bfin
RTEMS_CPU_MODEL=bf537
# This contains the compiler options necessary to select the CPU model
# and (hopefully) optimize for it.

View File

@@ -31,15 +31,10 @@ libbsp_a_SOURCES += ../../shared/bspreset.c
libbsp_a_SOURCES += console/console-io.c
libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/cache/cache.c
libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/mmu.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/interrupt.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/uart.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/clock.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/rtc.rel
libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/timer.rel
libbsp_a_SOURCES += ../../../../../../bsps/bfin/shared/interrupt.c
EXTRA_DIST += times
include $(top_srcdir)/../../../../automake/local.am
include $(srcdir)/../../../../../../bsps/bfin/shared/shared.am
include $(srcdir)/../../../../../../bsps/bfin/eZKit533/headers.am

View File

@@ -5,7 +5,6 @@
include $(RTEMS_ROOT)/make/custom/default.cfg
RTEMS_CPU=bfin
RTEMS_CPU_MODEL=bf533
# This contains the compiler options necessary to select the CPU model
# and (hopefully) optimize for it.

View File

@@ -1,83 +0,0 @@
ACLOCAL_AMFLAGS = -I ../../../aclocal
include $(top_srcdir)/../../../automake/compile.am
EXTRA_DIST =
noinst_PROGRAMS =
############
# Start of bf52x files
if bf52x
## INTERRUPT
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
############
noinst_PROGRAMS += mmu.rel
mmu_rel_SOURCES = mmu/mmu.c
mmu_rel_CPPFLAGS = $(AM_CPPFLAGS)
mmu_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
if bf52x
else
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)
clock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += rtc.rel
rtc_rel_SOURCES = clock/rtc.c clock/rtc.h
rtc_rel_CPPFLAGS = $(AM_CPPFLAGS)
rtc_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += uart.rel
uart_rel_SOURCES = serial/uart.c
uart_rel_CPPFLAGS = $(AM_CPPFLAGS)
uart_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += sport.rel
sport_rel_SOURCES = serial/sport.c
sport_rel_CPPFLAGS = $(AM_CPPFLAGS)
sport_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += spi.rel
spi_rel_SOURCES = serial/spi.c
spi_rel_CPPFLAGS = $(AM_CPPFLAGS)
spi_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += twi.rel
twi_rel_SOURCES = serial/twi.c
twi_rel_CPPFLAGS = $(AM_CPPFLAGS)
twi_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += timer.rel
timer_rel_SOURCES = timer/timer.c
timer_rel_CPPFLAGS = $(AM_CPPFLAGS)
timer_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
if HAS_NETWORKING
## network
noinst_PROGRAMS += network.rel
network_rel_SOURCES = network/ethernet.c
network_rel_CPPFLAGS = $(AM_CPPFLAGS)
network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
endif
include $(top_srcdir)/../../../automake/local.am

View File

@@ -1,11 +0,0 @@
This hierarchy contains support routines for the Analog Devices
Blackfin family of processors.
It is assumed that bsp.h includes <libcpu/bfxxx.h>, where xxx is
the processor type. This is how the libcpu modules determine which
processor variant they're being built for.
serial/sport* is currently just a placeholders. serial/twi* does not
contain enough code to do anything useful; it is however a start at an
I2C driver.

View File

@@ -1,642 +0,0 @@
/**
*@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

View File

@@ -1,81 +0,0 @@
/* 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;
}

View File

@@ -1,258 +0,0 @@
/*
* 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;
}

View File

@@ -1,35 +0,0 @@
## Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([rtems-c-src-lib-libcpu-bfin],[_RTEMS_VERSION],[https://devel.rtems.org/newticket])
RTEMS_TOP([../../../../..],[../../..])
RTEMS_SOURCE_TOP
RTEMS_BUILD_TOP
RTEMS_CANONICAL_TARGET_CPU
AM_INIT_AUTOMAKE([no-define foreign subdir-objects 1.12.2])
AM_MAINTAINER_MODE
RTEMS_ENV_RTEMSBSP
RTEMS_PROJECT_ROOT
RTEMS_PROG_CC_FOR_TARGET
AM_PROG_CC_C_O
RTEMS_CANONICALIZE_TOOLS
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
AC_CONFIG_FILES([Makefile
])
AC_OUTPUT

View File

@@ -1,196 +0,0 @@
/* 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);
}
}

View File

@@ -1,44 +0,0 @@
/* 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;
}

View File

@@ -1,880 +0,0 @@
/*
* 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;
}

View File

@@ -1,240 +0,0 @@
/* 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;
}

View File

@@ -1,2 +0,0 @@
/* placeholder */

View File

@@ -1,253 +0,0 @@
/* 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;
}

View File

@@ -1,528 +0,0 @@
/* 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;
}

View File

@@ -1,96 +0,0 @@
/**
* @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;
}