forked from Imagelibrary/rtems
bsp/bfin: Move libcpu content to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 = ðernetSoftc[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 = ðernetSoftc[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 = ðernetSoftc[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 = ðernetSoftc[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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/* placeholder */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user