2007-09-06 Daniel Hellstrom <daniel@gaisler.com>

New drivers: PCI, b1553BRM, SpaceWire(GRSPW), CAN (GRCAN,OC_CAN),
	Raw UART.
	* shared/1553/b1553brm.c, shared/1553/b1553brm_pci.c,
	shared/1553/b1553brm_rasta.c, shared/can/grcan.c,
	shared/can/grcan_rasta.c, shared/can/occan.c, shared/can/occan_pci.c,
	shared/spw/grspw.c, shared/spw/grspw_pci.c, shared/spw/grspw_rasta.c,
	shared/uart/apbuart.c, shared/uart/apbuart_pci.c,
	shared/uart/apbuart_rasta.c: New files missed in previous commit.
This commit is contained in:
Joel Sherrill
2007-09-06 13:27:25 +00:00
parent e16e0caf72
commit 226455f9ff
14 changed files with 8310 additions and 0 deletions

View File

@@ -1,3 +1,14 @@
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
New drivers: PCI, b1553BRM, SpaceWire(GRSPW), CAN (GRCAN,OC_CAN),
Raw UART.
* shared/1553/b1553brm.c, shared/1553/b1553brm_pci.c,
shared/1553/b1553brm_rasta.c, shared/can/grcan.c,
shared/can/grcan_rasta.c, shared/can/occan.c, shared/can/occan_pci.c,
shared/spw/grspw.c, shared/spw/grspw_pci.c, shared/spw/grspw_rasta.c,
shared/uart/apbuart.c, shared/uart/apbuart_pci.c,
shared/uart/apbuart_rasta.c: New files missed in previous commit.
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
* Makefile.am: Add the following new drivers: PCI, b1553BRM,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
/* Select PCI driver */
#define B1553BRM_NO_AMBA
#define B1553BRM_PCI
#undef B1553BRM_MAXDEVS
/* Use only 16K memory */
#define DMA_MEM_16K
/* Malloced memory or
* Card local memory
*/
#define B1553BRM_LOCAL_MEM
#define DONT_DEF_RAMON
/* memory must be aligned to a 128k boundary */
unsigned int brmpci_memarea_address;
#define B1553BRM_LOCAL_MEM_ADR brmpci_memarea_address
/* We have custom address tranlation for HW addresses */
#define B1553BRM_ADR_TO
/* No custom MEMAREA=>CPU used since BRM Core work with offsets
* in it's descriptors.
*/
#undef B1553BRM_ADR_FROM
/* Set registered device name */
#define B1553BRM_DEVNAME "/dev/brmpci0"
#define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[11]='0'+(no))
/* Any non-static function will begin with */
#define B1553BRM_PREFIX(name) b1553brmpci##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling b1553_interrupt_handler.
*/
#define B1553BRM_REG_INT(handler,irq,arg) \
if ( b1553brm_pci_int_reg ) \
b1553brm_pci_int_reg(handler,irq,arg);
#ifdef B1553BRM_ADR_TO
/* Translate a address within the Memory Region (memarea) into an Hardware
* device address. This address is put into hardware registers or descriptors
* so that the hardware can access the Memory Region.
* Example:
* An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
* the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000.
*/
unsigned int brmpci_hw_address;
static inline unsigned int memarea_to_hw(unsigned int addr) {
/* don't translate? */
if ( brmpci_hw_address == 0xffffffff )
return addr;
return ((addr & 0x000fffff) | brmpci_hw_address);
}
#endif
/* not used since BRM Core work with offsets */
#ifdef B1553BRM_ADR_FROM
unsigned int brmpci_cpu_access_address;
static inline unsigned int hw_to_cpu(unsigned int addr) {
/* don't translate? */
if ( brmpci_cpu_address == 0xffffffff )
return addr;
return ((addr & 0x0fffffff) | brmpci_cpu_address);
}
#endif
void (*b1553brm_pci_int_reg)(void *handler, int irq, void *arg) = 0;
static void b1553brmpci_interrupt_handler(int irq, void *arg);
#include "b1553brm.c"
/*
*
* memarea = preallocated memory somewhere, pointer to start of memory.
* hw_address = how to translate a memarea address into an HW device AMBA address.
*/
int b1553brm_pci_register(
amba_confarea_type *bus,
unsigned int clksel,
unsigned int clkdiv,
unsigned int brm_freq,
unsigned int memarea,
unsigned int hw_address
)
{
/* Setup configuration */
/* if zero malloc will be used */
brmpci_memarea_address = memarea;
brmpci_hw_address = hw_address;
#ifdef B1553BRM_ADR_FROM
brmpci_cpu_address = memarea & 0xf0000000;
#endif
/* Register the driver */
return B1553BRM_PREFIX(_register)(bus,clksel,clkdiv,brm_freq);
}
/* Call this from PCI interrupt handler
* irq = the irq number of the HW device local to that IRQMP controller
*
*/
static void b1553brmpci_interrupt_handler(int irq, void *arg){
brm_interrupt(arg);
}
#if 0
int b1553brm_pci_interrupt_handler(int irqmask){
int i;
unsigned int mask=0;
/* find minor */
for(i=0; i<brm_cores; i++){
if ( (1<<brms[i].irqno) & irqmask ){
mask |= 1<<brms[i].irqno;
brm_interrupt(&brms[i]);
/* more interrupts to scan for? */
if ( irqmask & ~mask )
return mask; /* handled */
}
}
return mask;
}
#endif

View File

@@ -0,0 +1,115 @@
/* Select PCI driver */
#define B1553BRM_NO_AMBA
#define B1553BRM_PCI
#undef B1553BRM_MAXDEVS
/* Use only 16K memory */
#define DMA_MEM_128K
/* Malloced memory or
* Card local memory
*/
#define B1553BRM_LOCAL_MEM
#define DONT_DEF_RAMON
/* memory must be aligned to a 128k boundary */
unsigned int brmrasta_memarea_address;
#define B1553BRM_LOCAL_MEM_ADR brmrasta_memarea_address
/* We have custom address tranlation for HW addresses */
#define B1553BRM_ADR_TO
/* No custom MEMAREA=>CPU used since BRM Core work with offsets
* in it's descriptors.
*/
#undef B1553BRM_ADR_FROM
/* Set registered device name */
#define B1553BRM_DEVNAME "/dev/brmrasta0"
#define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no))
/* Any non-static function will begin with */
#define B1553BRM_PREFIX(name) b1553brmrasta##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling b1553_interrupt_handler.
*/
#define B1553BRM_REG_INT(handler,irq,arg) \
if ( b1553brm_rasta_int_reg ) \
b1553brm_rasta_int_reg(handler,irq,arg);
#ifdef B1553BRM_ADR_TO
/* Translate a address within the Memory Region (memarea) into an Hardware
* device address. This address is put into hardware registers or descriptors
* so that the hardware can access the Memory Region.
* Example:
* An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
* the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000.
*/
unsigned int brmrasta_hw_address;
static inline unsigned int memarea_to_hw(unsigned int addr) {
/* don't translate? */
if ( brmrasta_hw_address == 0xffffffff )
return addr;
return ((addr & 0x0fffffff) | brmrasta_hw_address);
}
#endif
/* not used since BRM Core work with offsets */
#ifdef B1553BRM_ADR_FROM
unsigned int brmrasta_cpu_access_address;
static inline unsigned int hw_to_cpu(unsigned int addr) {
/* don't translate? */
if ( brmrasta_cpu_address == 0xffffffff )
return addr;
return ((addr & 0x0fffffff) | brmrasta_cpu_address);
}
#endif
void (*b1553brm_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
static void b1553brmrasta_interrupt_handler(int irq, void *arg);
#include "b1553brm.c"
/*
*
* memarea = preallocated memory somewhere, pointer to start of memory.
* hw_address = how to translate a memarea address into an HW device AMBA address.
*/
int b1553brm_rasta_register(
amba_confarea_type *bus,
unsigned int clksel,
unsigned int clkdiv,
unsigned int brm_freq,
unsigned int memarea,
unsigned int hw_address
)
{
/* Setup configuration */
/* if zero the malloc will be used */
brmrasta_memarea_address = memarea;
brmrasta_hw_address = hw_address;
#ifdef B1553BRM_ADR_FROM
brmrasta_cpu_address = memarea & 0xf0000000;
#endif
/* Register the driver */
return B1553BRM_PREFIX(_register)(bus,clksel,clkdiv,brm_freq);
}
/* Call this from RASTA interrupt handler
* irq = the irq number of the HW device local to that IRQMP controller
*
*/
static void b1553brmrasta_interrupt_handler(int irq, void *arg){
brm_interrupt(arg);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
#include <rasta.h>
/* PCI frequency */
#define SYS_FREQ_HZ 33000000
/*#define USE_AT697_RAM 1 */
/* memarea_to_hw(x)
*
* x: address in AT697 address space
*
* returns the address in the RASTA address space that can be used to access x with dma.
*
*/
#ifdef USE_AT697_RAM
static inline unsigned int memarea_to_hw(unsigned int addr) {
return ((addr & 0x0fffffff) | RASTA_PCI_BASE);
}
#else
static inline unsigned int memarea_to_hw(unsigned int addr) {
return ((addr & 0x0fffffff) | RASTA_LOCAL_SRAM);
}
#endif
#define MEMAREA_TO_HW(x) memarea_to_hw(x)
#define IRQ_CLEAR_PENDING(irqno)
#define IRQ_UNMASK(irqno)
#define IRQ_MASK(irqno)
#define IRQ_GLOBAL_DISABLE() sparc_disable_interrupts()
#define IRQ_GLOBAL_ENABLE() sparc_enable_interrupts()
#define GRCAN_REG_INT(handler,irqno,arg) \
if ( grcan_rasta_int_reg ) \
grcan_rasta_int_reg(handler,irqno,arg);
void (*grcan_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
#define GRCAN_PREFIX(name) grcan_rasta##name
/* We provide our own handler */
#define GRCAN_DONT_DECLARE_IRQ_HANDLER
#define GRCAN_REG_BYPASS_CACHE
#define GRCAN_DMA_BYPASS_CACHE
#define GRCAN_MAX_CORES 1
/* Custom Statically allocated memory */
#undef STATICALLY_ALLOCATED_TX_BUFFER
#undef STATICALLY_ALLOCATED_RX_BUFFER
#define STATIC_TX_BUF_SIZE 4096
#define STATIC_RX_BUF_SIZE 4096
#define TX_BUF_SIZE 4096
#define RX_BUF_SIZE 4096
#define STATIC_TX_BUF_ADDR(core) \
(grcan_rasta_rambase+(core)*(STATIC_TX_BUF_SIZE+STATIC_RX_BUF_SIZE))
#define STATIC_RX_BUF_ADDR(core) \
(grcan_rasta_rambase+(core)*(STATIC_TX_BUF_SIZE+STATIC_RX_BUF_SIZE)+STATIC_RX_BUF_SIZE)
#define GRCAN_DEVNAME "/dev/grcan0"
#define GRCAN_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
static int grcan_rasta_calc_memoffs(int maxcores, int corenum, unsigned int *mem_base, unsigned int *mem_end, unsigned int *bdtable_base);
void grcan_rasta_interrupt_handler(int irq, void *pDev);
unsigned int grcan_rasta_rambase;
#include "grcan.c"
int grcan_rasta_ram_register(amba_confarea_type *abus, int rambase)
{
grcan_rasta_rambase = rambase;
return GRCAN_PREFIX(_register)(abus);
}
#if 0
static void grcan_rasta_interrupt_handler(int v)
{
/* We know there is always only one GRCAN core in a RASTA chip... */
grcan_interrupt(&grcans[0]);
/*
struct grcan_priv *pDev = arg;
grcan_interrupt(pDev);
*/
}
#endif
void GRCAN_PREFIX(_interrupt_handler)(int irq, void *pDev)
{
grcan_interrupt(pDev);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
/* PCI cannot do byte accesses to addresses aligned byte wise
* Use alternative reg map.
*/
#define OCCAN_WORD_REGS
/* Set registered device name */
#define OCCAN_DEVNAME "/dev/occanpci0"
#define OCCAN_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no))
/* Any non-static function will begin with */
#define OCCAN_PREFIX(name) occanpci##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling b1553_interrupt_handler.
*/
#define OCCAN_REG_INT(handler,irq,arg) \
if ( occan_pci_int_reg ) \
occan_pci_int_reg(handler,irq,arg);
void (*occan_pci_int_reg)(void *handler, int irq, void *arg) = 0;
void occanpci_interrupt_handler(int irq, void *arg);
/* AMBA Bus is clocked using the PCI clock (33.3MHz) */
#define SYS_FREQ_HZ 33333333
/* Enable two redundant channels */
#define REDUNDANT_CHANNELS 2
#define OCCAN_SET_CHANNEL(priv,channel) occanpci_set_channel(priv,channel)
#include "occan.c"
/* Define method that sets redundant channel
* The channel select register:
* 0x00 = byte regs
* 0x40 = channel select
* 0x80 = word regs
*/
static void inline occanpci_set_channel(occan_priv *priv, int channel){
unsigned int *chan_sel = (unsigned int *)(((unsigned int)priv->regs & ~0xff)+0x40);
if ( channel == 0 )
*chan_sel = 0;
else
*chan_sel = 0xffffffff;
}
int occan_pci_register(amba_confarea_type *bus)
{
/* Setup configuration */
/* Register the driver */
return OCCAN_PREFIX(_register)(bus);
}
/* Call this from PCI interrupt handler
* irq = the irq number of the HW device local to that IRQMP controller
*
*/
void occanpci_interrupt_handler(int irq, void *arg){
occan_interrupt(arg);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
/* Select PCI driver */
#define GRSPW_PCI
#undef GRSPW_MAXDEVS
#undef DEBUG_SPACEWIRE_ONOFF
/* Only Malloced memory supported
*/
#undef GRSPW_LOCAL_MEM
/* memory must be aligned to a 128k boundary */
unsigned int grspwpci_memarea_address;
#define GRSPW_LOCAL_MEM_ADR grspwpci_memarea_address
/* We have custom address tranlation for HW addresses */
#define GRSPW_ADR_TO
/* MEMAREA=>CPU used when reading descriptor buffer pointers,
* they need to be translated from adresses used by GRSPW HW
* into CPU readable addresses.
*
* NOT NEEDED AS GRSPW DRIVER USES INDEXES TO GET DESCRIPTOR
* DATA POINTER ADDRESSES.
*/
#undef GRSPW_ADR_FROM
/* Set registered device name */
#define GRSPW_DEVNAME "/dev/grspwpci0"
#define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[13]='0'+(no))
/* Any non-static function will begin with */
#define GRSPW_PREFIX(name) grspwpci##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling b1553_interrupt_handler.
*/
#define GRSPW_REG_INT(handler,irq,arg) \
if ( grspw_pci_int_reg ) \
grspw_pci_int_reg(handler,irq,arg);
void (*grspw_pci_int_reg)(void *handler, int irq, void *arg) = 0;
#ifdef GRSPW_ADR_TO
/* Translate an address within the Memory Region (memarea) into an Hardware
* device address. This address is put into hardware registers or descriptors
* so that the hardware can access the Memory Region.
* Example:
* A local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
* the PCI address 0x40000000 will translate into LEON-AMBA address 0x40000000.
*/
unsigned int grspwpci_hw_address;
static inline unsigned int memarea_to_hw(unsigned int addr) {
/* don't translate? */
if ( grspwpci_hw_address == 0xffffffff )
return addr;
return ((addr & 0x0fffffff) | grspwpci_hw_address);
}
#endif
/* not used since BRM Core work with offsets */
#ifdef GRSPW_ADR_FROM
unsigned int grspwpci_cpu_access_address;
static inline unsigned int hw_to_cpu(unsigned int addr) {
/* don't translate? */
if ( grspwpci_cpu_address == 0xffffffff )
return addr;
return ((addr & 0x0fffffff) | grspwpci_cpu_address);
}
#endif
int grspwpci_interrupt_handler(int irq, void *arg);
#include "grspw.c"
/*
*
* memarea = preallocated memory somewhere, pointer to start of memory.
* hw_address = how to translate a memarea address into an HW device AMBA address.
*/
int grspw_pci_register(
amba_confarea_type *bus,
unsigned int memarea,
unsigned int hw_address
)
{
/* Setup configuration */
/* if zero the malloc will be used */
grspwpci_memarea_address = memarea;
grspwpci_hw_address = hw_address;
#ifdef GRSPW_ADR_FROM
grspwpci_cpu_address = memarea & 0xf0000000;
#endif
/* Register the driver */
return GRSPW_PREFIX(_register)(bus);
}
/* Call this from PCI interrupt handler
* irq = the irq number of the HW device local to that IRQMP controller
*
*/
int grspwpci_interrupt_handler(int irq, void *arg){
grspw_interrupt( (GRSPW_DEV *)arg );
}
#if 0
int grspw_pci_interrupt_handler(int irqmask){
int i;
unsigned int mask=0;
/* find minor */
for(i=0; i<spw_cores; i++){
if ( (1<<SPW_PARAM(i).irq) & irqmask ){
mask |= 1<<SPW_PARAM(i).irq;
grspw_interrupt(i);
/* more interrupts to scan for? */
if ( irqmask & ~mask )
return mask; /* handled */
}
}
return mask;
}
#endif

View File

@@ -0,0 +1,153 @@
/* Select PCI driver */
#define GRSPW_PCI
#undef GRSPW_MAXDEVS
#undef DEBUG_SPACEWIRE_ONOFF
/*#define DEBUG_SPACEWIRE_ONOFF*/
/*
* If USE_AT697_RAM is defined the RAM on the AT697 board will be used for DMA buffers (but rx message queue is always in AT697 ram).
* USE_AT697_DMA specifies whether the messages will be fetched using DMA or PIO.
*
* RASTA_PCI_BASE is the base address of the GRPCI AHB slave
*
*/
#define USE_AT697_RAM 1
#define USE_AT697_DMA 0
#define RASTA_PCI_BASE 0xe0000000
#define GRSPW_RASTA_MEM_OFF 0x21000
/* Make GRSPW driver use malloced or static memory
*/
#ifdef USE_AT697_RAM
#undef GRSPW_STATIC_MEM
#else
#define GRSPW_STATIC_MEM
#define GRSPW_CALC_MEMOFS(maxcores,corenum,ptr_mem_base,ptr_mem_end,ptr_bdtable_base) \
grspw_rasta_calc_memoffs((maxcores),(corenum),(ptr_mem_base),(ptr_mem_end),(ptr_bdtable_base))
#endif
/* We have custom address tranlation for HW addresses */
#define GRSPW_ADR_TO
/* MEMAREA=>CPU used when reading descriptor buffer pointers,
* they need to be translated from adresses used by GRSPW HW
* into CPU readable addresses.
*
* NOT NEEDED AS GRSPW DRIVER USES INDEXES TO GET DESCRIPTOR
* DATA POINTER ADDRESSES.
*/
#undef GRSPW_ADR_FROM
/* Set registered device name */
#define GRSPW_DEVNAME "/dev/grspwrasta0"
#define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[15]='0'+(no))
/* Any non-static function will begin with */
#define GRSPW_PREFIX(name) grspwrasta##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling grspw_interrupt_handler.
*/
#define GRSPW_REG_INT(handler,irq,arg) \
if ( grspw_rasta_int_reg ) \
grspw_rasta_int_reg(handler,irq,arg);
#define GRSPW_DONT_BYPASS_CACHE
#ifdef GRSPW_ADR_TO
/* Translate a address within the Memory Region (memarea) into an Hardware
* device address. This address is put into hardware registers or descriptors
* so that the hardware can access the Memory Region.
* Example:
* An local AMBA access at 0xe0000000 will translate into PCI address 0x40000000,
* the PCI address 0x40000000 will translate into CPU-AMBA address 0x40000000.
*/
static inline unsigned int memarea_to_hw(unsigned int addr) {
return ((addr & 0x0fffffff) | RASTA_PCI_BASE);
}
#endif
void (*grspw_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
static int grspw_rasta_calc_memoffs(int maxcores, int corenum, unsigned int *mem_base, unsigned int *mem_end, unsigned int *bdtable_base);
int grspw_rasta_interrupt_handler(unsigned int status);
void grspwrasta_interrupt_handler(int irq, void *pDev);
#include "grspw.c"
unsigned int grspw_rasta_memarea_address;
/* Register RASTA GRSPW driver.
*
* memarea = preallocated memory somewhere, pointer to start of memory.
*/
int grspw_rasta_register(
amba_confarea_type *bus,
unsigned int ram_base
)
{
/* Setup configuration */
/* if zero the malloc will be used */
grspw_rasta_memarea_address = ram_base + GRSPW_RASTA_MEM_OFF;
/* Register the driver */
return GRSPW_PREFIX(_register)(bus);
}
#if 0
/* Call this from PCI interrupt handler, simply figures out
* which GRSPW core was responsible for the IRQ (may be multiple).
* v = status of the PCI/AMBA MCPU IRQ CTRL
*/
int grspw_rasta_interrupt_handler(unsigned int status)
{
int minor;
for(minor = 0; minor < spw_cores; minor++) {
if (status & (1<<grspw_devs[minor].irq) ) {
grspw_interrupt(&grspw_devs[minor]);
}
}
}
#endif
void GRSPW_PREFIX(_interrupt_handler)(int irq, void *pDev)
{
grspw_interrupt(pDev);
}
#ifdef GRSPW_STATIC_MEM
/*
* --------------------------------------- <-
* | Core1: BD TABLE 1 and 2 |
* | Core2: BD TABLE 1 and 2 |
* | Core3: BD TABLE 1 and 2 |
* |-------------------------------------|
* | Core1: rx data buf + rx header buf |
* | Core2: rx data buf + rx header buf |
* | Core3: rx data buf + rx header buf |
* ---------------------------------------
*/
static int grspw_rasta_calc_memoffs(int maxcores, int corenum, unsigned int *mem_base, unsigned int *mem_end, unsigned int *bdtable_base)
{
if ( maxcores > 3 )
return -1;
if ( bdtable_base )
*bdtable_base = grspw_rasta_memarea_address + corenum*2*SPACEWIRE_BDTABLE_SIZE;
if ( mem_base )
*mem_base = grspw_rasta_memarea_address + coremax*2*SPACEWIRE_BDTABLE_SIZE + corenum*BUFMEM_PER_LINK;
if ( mem_end )
*mem_end = grspw_rasta_memarea_address + coremax*2*SPACEWIRE_BDTABLE_SIZE + (corenum+1)*BUFMEM_PER_LINK;
return 0;
}
#endif

View File

@@ -0,0 +1,885 @@
/*
* This file contains the driver for the APBUART serial port.
* No console driver, only char driver.
*
* COPYRIGHT (c) 2007.
* Gaisler Research.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
*
* 2007-07-11, Daniel Hellstrom <daniel@gaisler.com>
* Added ioctl command APBUART_CLR_STATS
*/
#include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <assert.h>
#include <rtems/bspIo.h>
#include <string.h>
#include <ambapp.h>
#include <apbuart.h>
#ifndef DEFAULT_TXBUF_SIZE
#define DEFAULT_TXBUF_SIZE 32
#endif
#ifndef DEFAULT_RXBUF_SIZE
#define DEFAULT_RXBUF_SIZE 32
#endif
#ifndef APBUART_PREFIX
#define APBUART_PREFIX(name) apbuart##name
#endif
#if !defined(APBUART_DEVNAME) || !defined(APBUART_DEVNAME_NO)
#undef APBUART_DEVNAME
#undef APBUART_DEVNAME_NO
#define APBUART_DEVNAME "/dev/apbuart0"
#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
#endif
#ifndef APBUART_REG_INT
#define APBUART_REG_INT(handler,irq,arg) set_vector(handler,irq+0x10,1)
#endif
/* Default to 40MHz system clock */
/*#ifndef SYS_FREQ_HZ
#define SYS_FREQ_HZ 40000000
#endif*/
typedef struct {
int size;
unsigned char *buf,
*tail,
*head,
*max;
int full; /* no more place in fifo */
} apbuart_fifo;
static apbuart_fifo *apbuart_fifo_create(int size);
static void apbuart_fifo_free(apbuart_fifo *fifo);
static inline int apbuart_fifo_isFull(apbuart_fifo *fifo);
static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo);
static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c);
static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c);
static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c);
static void inline apbuart_fifo_skip(apbuart_fifo *fifo);
static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
typedef struct {
ambapp_apb_uart *regs;
int irq;
int minor;
int scaler;
unsigned int baud;
int txblk; /* Make write block until at least 1 char has
* been put into software send fifo
*/
int tx_flush; /* Set this to block until all data has
* placed into the hardware send fifo
*/
int rxblk; /* Make read block until at least 1 char has
* been received (or taken from software fifo).
*/
int started; /* Set to 1 when in running mode */
int ascii_mode; /* Set to 1 to make \n be printed as \r\n */
/* TX/RX software FIFO Buffers */
apbuart_fifo *txfifo;
apbuart_fifo *rxfifo;
apbuart_stats stats;
rtems_id dev_sem;
rtems_id rx_sem;
rtems_id tx_sem;
} apbuart_priv;
static int dev_cnt;
static apbuart_priv *apbuarts;
static unsigned int sys_freq_hz;
#define APBUART_DRIVER_TABLE_ENTRY { apbuart_initialize, apbuart_open, apbuart_close, apbuart_read, apbuart_write, apbuart_control }
static rtems_driver_address_table apbuart_driver = APBUART_DRIVER_TABLE_ENTRY;
static amba_confarea_type *amba_bus;
static void apbuart_interrupt(apbuart_priv *uart);
static void apbuart_interrupt_handler(rtems_vector_number v);
static void apbuart_hw_close(apbuart_priv *uart);
static void apbuart_hw_open(apbuart_priv *uart);
/* Uncomment for debug output */
/* #define DEBUG 1
#define FUNCDEBUG 1 */
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#ifdef FUNCDEBUG
#define FUNCDBG(x...) printk(x)
#else
#define FUNCDBG(x...)
#endif
#ifndef READ_REG
#define READ_REG(address) _APBUART_READ_REG((unsigned int)(address))
static __inline__ unsigned int _APBUART_READ_REG(unsigned int addr) {
unsigned int tmp;
asm(" lda [%1]1, %0 "
: "=r"(tmp)
: "r"(addr)
);
return tmp;
}
#endif
#if 0
static int apbuart_outbyte_try(ambapp_apb_uart *regs, unsigned char ch)
{
if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_THE) == 0 )
return -1; /* Failed */
/* There is room in fifo, put ch in it */
regs->data = (unsigned int) ch;
return 0;
}
static int apbuart_inbyte_try(ambapp_apb_uart *regs)
{
unsigned int status;
/* Clear errors if any */
if ( (status=READ_REG(&regs->status)) & LEON_REG_UART_STATUS_ERR) {
regs->status = status & ~LEON_REG_UART_STATUS_ERR;
}
/* Is Data available? */
if ( (READ_REG(&regs->status) & LEON_REG_UART_STATUS_DR) == 0 )
return -1; /* No data avail */
/* Return Data */
return (int)READ_REG(&regs->data);
}
static int apbuart_write_support(apbuart_priv *uart, const char *buf, int len)
{
int nwrite = 0;
while (nwrite < len) {
if ( apbuart_outbyte_try(minor, *buf++) ){
/* TX Fifo full */
}
nwrite++;
}
return nwrite;
}
#endif
static void apbuart_hw_open(apbuart_priv *uart){
unsigned int scaler;
/* Calculate Baudrate */
if ( uart->scaler > 0 ) {
scaler = uart->scaler;
}else{
scaler = (((sys_freq_hz*10)/(uart->baud*8))-5)/10;
}
/* Set new baud rate */
uart->regs->scaler = scaler;
/* Enable receiver & Transmitter */
uart->regs->ctrl = APBUART_CTRL_RE | APBUART_CTRL_RF | APBUART_CTRL_RI | APBUART_CTRL_TI;
}
static void apbuart_hw_close(apbuart_priv *uart){
/* disable receiver & transmitter & all IRQs */
uart->regs->ctrl = 0;
}
/* interrupt handler */
static void apbuart_interrupt_handler(rtems_vector_number v){
int minor;
/* convert to */
for(minor = 0; minor < dev_cnt; minor++) {
if ( v == (apbuarts[minor].irq+0x10) ) {
apbuart_interrupt(&apbuarts[minor]);
return;
}
}
}
/* The interrupt handler, taking care of the
* APBUART hardware
*/
static void apbuart_interrupt(apbuart_priv *uart){
unsigned int status;
int empty;
unsigned char c, *next_char;
int signal;
/* Clear & record any error */
status = READ_REG(&uart->regs->status);
if ( status & (APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE) ){
/* Data overrun */
if ( status & APBUART_STATUS_OV ){
uart->stats.hw_dovr++;
}
/* Parity error */
if ( status & APBUART_STATUS_PE ){
uart->stats.hw_parity++;
}
/* Framing error */
if ( status & APBUART_STATUS_FE ){
uart->stats.hw_frame++;
}
uart->regs->status = status & ~(APBUART_STATUS_OV|APBUART_STATUS_PE|APBUART_STATUS_FE);
}
/* Empty RX fifo into software fifo */
signal = 0;
while ( (status=READ_REG(&uart->regs->status)) & APBUART_STATUS_DR ){
c = READ_REG(&uart->regs->data);
if ( apbuart_fifo_isFull(uart->rxfifo) ){
uart->stats.sw_dovr++;
DBG("]");
break;
}
/* put into fifo */
apbuart_fifo_put(uart->rxfifo,c);
/* bump RX counter */
uart->stats.rx_cnt++;
signal = 1;
}
/* Wake RX thread if any */
if ( signal )
rtems_semaphore_release(uart->rx_sem);
/* If room in HW fifo and we got more chars to be sent */
if ( !(status & APBUART_STATUS_TF) ){
if ( apbuart_fifo_isEmpty(uart->txfifo) ){
/* Turn off TX interrupt when no data is to be sent */
if ( status & APBUART_STATUS_TE ){
uart->regs->ctrl = READ_REG(&uart->regs->ctrl) & ~APBUART_CTRL_TF;
DBG("?");
}
return;
}
/* signal when there will be more room in SW fifo */
if ( apbuart_fifo_isFull(uart->txfifo) )
signal = 1;
do{
/* Put data into HW TX fifo */
apbuart_fifo_peek(uart->txfifo,&next_char);
c = *next_char;
if ( uart->ascii_mode && ( c == '\n') ){
uart->regs->data = '\n';
*next_char = '\r'; /* avoid sending mutiple '\n' or '\r' */
}else{
uart->regs->data = c;
apbuart_fifo_skip(uart->txfifo); /* remove sent char from fifo */
}
uart->regs->ctrl = READ_REG(&uart->regs->ctrl) | APBUART_CTRL_TE | APBUART_CTRL_TF;
DBG("!");
}while(!(empty=apbuart_fifo_isEmpty(uart->txfifo)) &&
!((status=READ_REG(&uart->regs->status))&APBUART_STATUS_TF) );
/* Wake userspace thread, on empty or full fifo
* This makes tx_flush and block work.
*/
if ( signal || empty ){
rtems_semaphore_release(uart->tx_sem);
}
}
}
int APBUART_PREFIX(_register)(amba_confarea_type *bus) {
rtems_status_code r;
rtems_device_major_number m;
amba_bus = bus;
FUNCDBG("apbuart_register:\n");
if ((r = rtems_io_register_driver(0, &apbuart_driver, &m)) == RTEMS_SUCCESSFUL) {
DBG("APBUART driver successfully registered, major: %d\n", m);
} else {
switch(r) {
case RTEMS_TOO_MANY:
printk("APBUART rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); return -1;
case RTEMS_INVALID_NUMBER:
printk("APBUART rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); return -1;
case RTEMS_RESOURCE_IN_USE:
printk("APBUART rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); return -1;
default:
printk("APBUART rtems_io_register_driver failed\n");
return -1;
}
}
return 0;
}
static rtems_device_driver apbuart_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
rtems_status_code status;
int i;
amba_apb_device dev;
char fs_name[20];
FUNCDBG("apbuart_initialize\n");
/* Find all APB UART devices */
dev_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_APBUART);
if ( dev_cnt < 1 ){
/* Failed to find any CAN cores! */
printk("APBUART: Failed to find any APBUART cores\n\r");
return -1;
}
strcpy(fs_name,APBUART_DEVNAME);
DBG("Found %d APBUART(s)\n\r",dev_cnt);
/* Allocate memory for device structures */
apbuarts = malloc(sizeof(apbuart_priv) * dev_cnt);
if ( !apbuarts ){
printk("APBUART: Failed to allocate SW memory\n\r");
return -1;
}
memset(apbuarts,0,sizeof(sizeof(apbuart_priv) * dev_cnt));
/* Detect System Frequency from initialized timer */
#ifndef SYS_FREQ_HZ
#if defined(LEON3)
/* LEON3: find timer address via AMBA Plug&Play info */
{
amba_apb_device gptimer;
LEON3_Timer_Regs_Map *tregs;
if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
sys_freq_hz = (tregs->scaler_reload+1)*1000*1000;
DBG("APBUART: detected %dHZ system frequency\n\r",sys_freq_hz);
}else{
sys_freq_hz = 40000000; /* Default to 40MHz */
printk("APBUART: Failed to detect system frequency\n\r");
}
}
#elif defined(LEON2)
/* LEON2: use hardcoded address to get to timer */
{
LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
sys_freq_hz = (regs->Scaler_Reload+1)*1000*1000;
}
#else
#error CPU not supported for OC_CAN driver
#endif
#else
/* Use hardcoded frequency */
sys_freq_hz = SYS_FREQ_HZ;
#endif
for(i=0; i<dev_cnt; i++){
/* Get AMBA AHB device info from Plug&Play */
amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_APBUART,&dev,i);
printk("APBUART[%d]: at 0x%x irq %d (0x%x)\n\r",i,dev.start,dev.irq,(unsigned int)&apbuarts[i]);
apbuarts[i].regs = (ambapp_apb_uart *)dev.start;
apbuarts[i].irq = dev.irq;
apbuarts[i].minor = i;
/* Clear HW regs */
apbuarts[i].regs->status = 0;
apbuarts[i].regs->ctrl = 0;
/* Allocate default software buffers */
apbuarts[i].txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);
apbuarts[i].rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
if ( !apbuarts[i].txfifo || !apbuarts[i].rxfifo )
rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
APBUART_DEVNAME_NO(fs_name,i);
/* Bind name to device */
DBG("APBUART[%d]: binding to name %s\n\r",i,fs_name);
status = rtems_io_register_name(fs_name, major, i);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred(status);
/* Setup interrupt handler for each channel */
APBUART_REG_INT(APBUART_PREFIX(_interrupt_handler), apbuarts[i].irq, &apbuarts[i]);
/* Device A Semaphore created with count = 1 */
if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'D', '0'+i),
1,
RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
0,
&apbuarts[i].dev_sem) != RTEMS_SUCCESSFUL )
return RTEMS_INTERNAL_ERROR;
if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'T', '0'+i),
1,
RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
0,
&apbuarts[i].tx_sem) != RTEMS_SUCCESSFUL )
return RTEMS_INTERNAL_ERROR;
if ( rtems_semaphore_create(rtems_build_name('A', 'U', 'R', '0'+i),
1,
RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
0,
&apbuarts[i].rx_sem) != RTEMS_SUCCESSFUL )
return RTEMS_INTERNAL_ERROR;
}
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
apbuart_priv *uart;
FUNCDBG("apbuart_open: major %d, minor %d\n", major, minor);
if ( (minor < 0) || (minor >= dev_cnt) ) {
DBG("Wrong minor %d\n", minor);
return RTEMS_INVALID_NAME;
}
uart = &apbuarts[minor];
if (rtems_semaphore_obtain(uart->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
DBG("apbuart_open: resource in use\n");
return RTEMS_RESOURCE_IN_USE;
}
/* Clear HW regs */
uart->regs->status = 0;
uart->regs->ctrl = 0;
/* Set Defaults */
/* 38400 baudrate */
uart->scaler = 0; /* use uart->baud */
uart->baud = 38400;
/* Default to Blocking mode */
uart->txblk = 1;
uart->rxblk = 1;
/* Default to no flush mode */
uart->tx_flush = 0;
/* non-ascii mode */
uart->ascii_mode = 0;
/* not started */
uart->started = 0;
if ( !uart->txfifo || (uart->txfifo->size!=DEFAULT_TXBUF_SIZE) ){
apbuart_fifo_free(uart->txfifo);
uart->txfifo = apbuart_fifo_create(DEFAULT_TXBUF_SIZE);
}
if ( !uart->rxfifo || (uart->rxfifo->size!=DEFAULT_RXBUF_SIZE) ){
apbuart_fifo_free(uart->rxfifo);
uart->rxfifo = apbuart_fifo_create(DEFAULT_RXBUF_SIZE);
}
if ( !uart->rxfifo || !uart->txfifo ){
/* Failed to get memory */
return RTEMS_NO_MEMORY;
}
/* Now user must call ioctl(START,0) to begin */
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
apbuart_priv *uart = &apbuarts[minor];
FUNCDBG("apbuart_close[%d]:\n",minor);
apbuart_hw_close(uart);
/* Software state will be set when open is called again */
rtems_semaphore_release(uart->rx_sem);
rtems_semaphore_release(uart->tx_sem);
uart->started = 0;
rtems_semaphore_release(uart->dev_sem);
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
rtems_libio_rw_args_t *rw_args;
unsigned int count = 0, oldLevel;
unsigned char *buf;
apbuart_priv *uart = &apbuarts[minor];
rw_args = (rtems_libio_rw_args_t *) arg;
FUNCDBG("apbuart_read\n");
buf = (unsigned char *)rw_args->buffer;
if ( (rw_args->count < 1) || !buf )
return RTEMS_INVALID_NAME; /* EINVAL */
rtems_interrupt_disable(oldLevel);
do {
if ( (unsigned int)uart < 0x40000000 ) {
printk("UART %x is screwed\n",uart);
}
/* Read from SW fifo */
if ( apbuart_fifo_get(uart->rxfifo,&buf[count]) != 0 ){
/* non blocking or read at least 1 byte */
if ( (count > 0) || (!uart->rxblk) )
break; /* Return */
rtems_interrupt_enable(oldLevel);
/* Block thread until a char is received */
rtems_semaphore_obtain(uart->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
rtems_interrupt_disable(oldLevel);
continue;
}
/* Got char from SW FIFO */
count++;
} while (count < rw_args->count );
rtems_interrupt_enable(oldLevel);
rw_args->bytes_moved = count;
if (count == 0)
return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
rtems_libio_rw_args_t *rw_args;
unsigned int count, oldLevel, ctrl;
unsigned char *buf;
apbuart_priv *uart = &apbuarts[minor];
int direct=0;
rw_args = (rtems_libio_rw_args_t *) arg;
FUNCDBG("apbuart_write\n");
buf = rw_args->buffer;
if ( rw_args->count < 1 || !buf )
return RTEMS_INVALID_NAME; /* EINVAL */
count = 0;
rtems_interrupt_disable(oldLevel);
/* Do we need to start to send first char direct via HW
* to get IRQ going.
*/
ctrl = READ_REG(&uart->regs->ctrl);
if ( (ctrl & APBUART_CTRL_TF) == 0 ){
/* TX interrupt is disabled ==>
* SW FIFO is empty and,
* HW FIFO empty
*/
uart->regs->ctrl = ctrl | APBUART_CTRL_TF;
if ( uart->ascii_mode && (buf[0] == '\n') ){
uart->regs->data = '\r';
}else{
uart->regs->data = buf[0];
count++;
}
uart->regs->ctrl = ctrl | APBUART_CTRL_TE | APBUART_CTRL_TF;
direct = 1;
}
while( count < rw_args->count ) {
/* write to HW FIFO direct skipping SW FIFO */
if ( direct && ((READ_REG(&uart->regs->status) & APBUART_STATUS_TF) == 0) ){
uart->regs->data = buf[count];
}
/* write to SW FIFO */
else if ( apbuart_fifo_put(uart->txfifo,buf[count]) ){
direct = 0;
DBG("APBUART[%d]: write: SW FIFO Full\n\r",minor);
/* is full, block? */
if ( ((count < 1) && uart->txblk) || uart->tx_flush ){
rtems_interrupt_enable(oldLevel);
rtems_semaphore_obtain(uart->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
rtems_interrupt_disable(oldLevel);
/* Do we need to start to send first char direct via HW
* to get IRQ going.
*/
ctrl = READ_REG(&uart->regs->ctrl);
if ( (ctrl & APBUART_CTRL_TF) == 0 ){
/* TX interrupt is disabled ==>
* SW FIFO is empty and,
* HW FIFO empty
*/
uart->regs->ctrl = ctrl | APBUART_CTRL_TF;
if ( uart->ascii_mode && (buf[count] == '\n') ){
uart->regs->data = '\r';
}else{
uart->regs->data = buf[count];
count++;
}
uart->regs->ctrl = ctrl | APBUART_CTRL_TF | APBUART_CTRL_TE;
direct = 1;
}
continue;
}
/* don't block, return current status */
break;
}else{
direct = 0;
}
count++;
}
rtems_interrupt_enable(oldLevel);
rw_args->bytes_moved = count;
if (count == 0)
return RTEMS_TIMEOUT; /* ETIMEDOUT should be EAGAIN/EWOULDBLOCK */
return RTEMS_SUCCESSFUL;
}
static rtems_device_driver apbuart_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
unsigned int *data = ioarg->buffer;
apbuart_priv *uart = &apbuarts[minor];
int size;
unsigned int baudrate, blocking;
apbuart_stats *stats;
FUNCDBG("apbuart_control [%i,%i]\n",major, minor);
if (!ioarg)
return RTEMS_INVALID_NAME;
ioarg->ioctl_return = 0;
switch(ioarg->command) {
/* Enable Receiver & transmitter */
case APBUART_START:
if ( uart->started )
return RTEMS_INVALID_NAME;
apbuart_hw_open(uart);
uart->started = 1;
break;
/* Close Receiver & transmitter */
case APBUART_STOP:
if ( !uart->started )
return RTEMS_INVALID_NAME;
apbuart_hw_close(uart);
uart->started = 0;
break;
/* Set RX FIFO Software buffer length
* It is only possible to change buffer size in
* non-running mode.
*/
case APBUART_SET_RXFIFO_LEN:
if ( uart->started )
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
size = (int)ioarg->buffer;
if ( size < 1 )
return RTEMS_INVALID_NAME; /* EINVAL */
/* Free old buffer */
apbuart_fifo_free(uart->rxfifo);
/* Allocate new buffer & init it */
uart->rxfifo = apbuart_fifo_create(size);
if ( !uart->rxfifo )
return RTEMS_NO_MEMORY;
break;
/* Set TX FIFO Software buffer length
* It is only possible to change buffer size
* while in non-running mode.
*/
case APBUART_SET_TXFIFO_LEN:
if ( uart->started )
return RTEMS_RESOURCE_IN_USE; /* EBUSY */
size = (int)ioarg->buffer;
if ( size < 1 )
return RTEMS_INVALID_NAME; /* EINVAL */
/* Free old buffer */
apbuart_fifo_free(uart->txfifo);
/* Allocate new buffer & init it */
uart->txfifo = apbuart_fifo_create(size);
if ( !uart->txfifo )
return RTEMS_NO_MEMORY;
break;
case APBUART_SET_BAUDRATE:
/* Set baud rate of */
baudrate = (int)ioarg->buffer;
if ( (baudrate < 1) || (baudrate > 115200) ){
return RTEMS_INVALID_NAME;
}
uart->scaler = 0; /* use uart->baud */
uart->baud = baudrate;
break;
case APBUART_SET_SCALER:
/* use uart->scaler not uart->baud */
uart->scaler = data[0];
break;
case APBUART_SET_BLOCKING:
blocking = (unsigned int)ioarg->buffer;
uart->rxblk = ( blocking & APBUART_BLK_RX );
uart->txblk = ( blocking & APBUART_BLK_TX );
uart->tx_flush = ( blocking & APBUART_BLK_FLUSH );
break;
case APBUART_GET_STATS:
stats = (void *)ioarg->buffer;
if ( !stats )
return RTEMS_INVALID_NAME;
/* Copy Stats */
*stats = uart->stats;
break;
case APBUART_CLR_STATS:
/* Clear/reset Stats */
memset(&uart->stats,0,sizeof(uart->stats));
break;
case APBUART_SET_ASCII_MODE:
uart->ascii_mode = (int)ioarg->buffer;
break;
default:
return RTEMS_NOT_DEFINED;
}
return RTEMS_SUCCESSFUL;
}
/******************* APBUART FIFO implementation ***********************/
static apbuart_fifo *apbuart_fifo_create(int size){
apbuart_fifo *fifo;
fifo = (apbuart_fifo *) malloc( size + sizeof(apbuart_fifo));
if ( fifo ){
/* Init fifo */
fifo->size = size;
fifo->buf = (char *)(fifo+1);
fifo->tail = fifo->buf;
fifo->head = fifo->buf;
fifo->max = &fifo->buf[size-1];
fifo->full=0;
}
return fifo;
}
static void apbuart_fifo_free(apbuart_fifo *fifo){
if ( fifo )
free(fifo);
}
static inline int apbuart_fifo_isFull(apbuart_fifo *fifo){
return fifo->full;
}
static inline int apbuart_fifo_isEmpty(apbuart_fifo *fifo){
if ( (fifo->head == fifo->tail) && !fifo->full )
return -1;
return 0;
}
static int apbuart_fifo_put(apbuart_fifo *fifo, unsigned char c){
if ( !fifo->full ){
*fifo->head = c;
fifo->head = (fifo->head >= fifo->max ) ? fifo->buf : fifo->head+1;
if ( fifo->head == fifo->tail )
fifo->full = -1;
return 0;
}
return -1;
}
static int apbuart_fifo_get(apbuart_fifo *fifo, unsigned char *c){
if ( apbuart_fifo_isEmpty(fifo) )
return -1;
if ( c )
*c = *fifo->tail;
fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
fifo->full = 0;
return 0;
}
static int inline apbuart_fifo_peek(apbuart_fifo *fifo, unsigned char **c){
if ( apbuart_fifo_isEmpty(fifo) )
return -1;
if ( c )
*c = fifo->tail;
return 0;
}
static void inline apbuart_fifo_skip(apbuart_fifo *fifo){
if ( !apbuart_fifo_isEmpty(fifo) ){
fifo->tail = (fifo->tail >= fifo->max ) ? fifo->buf : fifo->tail+1;
fifo->full = 0;
}
}

View File

@@ -0,0 +1,42 @@
#undef DEBUG
/* Set registered device name */
#define APBUART_DEVNAME "/dev/apbupci0"
#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[12]='0'+(no))
/* Any non-static function will begin with */
#define APBUART_PREFIX(name) apbuartpci##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling apbuartpci_interrupt_handler.
*/
#define APBUART_REG_INT(handler,irq,arg) \
if ( apbuart_pci_int_reg ) \
apbuart_pci_int_reg(handler,irq,arg);
void (*apbuart_pci_int_reg)(void *handler, int irq, void *arg) = 0;
void apbuartpci_interrupt_handler(int irq, void *arg);
/* AMBA Bus is clocked using the PCI clock (33.3MHz) */
#define SYS_FREQ_HZ 33333333
#include "apbuart.c"
int apbuart_pci_register(amba_confarea_type *bus)
{
/* Setup configuration */
/* Register the driver */
return APBUART_PREFIX(_register)(bus);
}
/* Call this from PCI interrupt handler
* irq = the irq number of the HW device local to that IRQMP controller
*
*/
void apbuartpci_interrupt_handler(int irq, void *arg){
apbuart_interrupt(arg);
}

View File

@@ -0,0 +1,42 @@
#undef DEBUG
/* Set registered device name */
#define APBUART_DEVNAME "/dev/apburasta0"
#define APBUART_DEVNAME_NO(devstr,no) ((devstr)[14]='0'+(no))
/* Any non-static function will begin with */
#define APBUART_PREFIX(name) apbuartrasta##name
/* do nothing, assume that the interrupt handler is called
* setup externally calling apbuartrasta_interrupt_handler.
*/
#define APBUART_REG_INT(handler,irq,arg) \
if ( apbuart_rasta_int_reg ) \
apbuart_rasta_int_reg(handler,irq,arg);
void (*apbuart_rasta_int_reg)(void *handler, int irq, void *arg) = 0;
void apbuartrasta_interrupt_handler(int irq, void *arg);
/* AMBA Bus is clocked using the RASTA internal clock (30MHz) */
#define SYS_FREQ_HZ 30000000
#include "apbuart.c"
int apbuart_rasta_register(amba_confarea_type *bus)
{
/* Setup configuration */
/* Register the driver */
return APBUART_PREFIX(_register)(bus);
}
/* Call this from RASTA interrupt handler
* irq = the irq number of the HW device local to that IRQMP controller
*
*/
void apbuartrasta_interrupt_handler(int irq, void *arg){
apbuart_interrupt(arg);
}