summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2007-11-30 16:48:06 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2007-11-30 16:48:06 +0000
commitd805da0ef1b0c69daab0e9dacba34ee4d62ee285 (patch)
tree402d9ebc3bff8b5eb85580b27241b2c9dd8f6599 /c
parentRegnerate. (diff)
downloadrtems-d805da0ef1b0c69daab0e9dacba34ee4d62ee285.tar.bz2
2007-11-30 Daniel Hellstrom <daniel@gaisler.com>
* shared/can/grcan.c, shared/can/grcan_rasta.c, shared/include/ambapp.h: GRCAN CAN driver. Fixes Interrupt enabling/disabling in the driver, interrupt may not be restored correctly. Implements the baud rate calculation routine. Removed unnecessary printk. Fixed scanning to support GRCAN and GRHCAN hardware. Added GRCAN device number to ambapp.h.
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/sparc/ChangeLog9
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/grcan.c203
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c7
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/ambapp.h6
4 files changed, 184 insertions, 41 deletions
diff --git a/c/src/lib/libbsp/sparc/ChangeLog b/c/src/lib/libbsp/sparc/ChangeLog
index 17a2d5394e..81c8350043 100644
--- a/c/src/lib/libbsp/sparc/ChangeLog
+++ b/c/src/lib/libbsp/sparc/ChangeLog
@@ -1,3 +1,12 @@
+2007-11-30 Daniel Hellstrom <daniel@gaisler.com>
+
+ * shared/can/grcan.c, shared/can/grcan_rasta.c,
+ shared/include/ambapp.h: GRCAN CAN driver. Fixes Interrupt
+ enabling/disabling in the driver, interrupt may not be restored
+ correctly. Implements the baud rate calculation routine. Removed
+ unnecessary printk. Fixed scanning to support GRCAN and GRHCAN
+ hardware. Added GRCAN device number to ambapp.h.
+
2007-10-11 Daniel Hellstrom <daniel@gaisler.com>
* shared/can/occan.c: Fixes bug in OC-CAN baud rate calculator. The
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan.c b/c/src/lib/libbsp/sparc/shared/can/grcan.c
index a21d71f01a..0eb08585be 100644
--- a/c/src/lib/libbsp/sparc/shared/can/grcan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/grcan.c
@@ -26,7 +26,6 @@
#include <grcan.h>
#include <ambapp.h>
-#include <pci.h>
#define WRAP_AROUND_TX_MSGS 1
#define WRAP_AROUND_RX_MSGS 2
@@ -43,12 +42,16 @@
#define RX_BUF_SIZE ((3*BLOCK_SIZE)*16)
#endif
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
#ifndef IRQ_GLOBAL_DISABLE
- #define IRQ_GLOBAL_DISABLE() sparc_disable_interrupts()
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
#endif
#ifndef IRQ_GLOBAL_ENABLE
- #define IRQ_GLOBAL_ENABLE() sparc_enable_interrupts()
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
#endif
#ifndef IRQ_CLEAR_PENDING
@@ -90,6 +93,10 @@
#define GRCAN_DEFAULT_BAUD 500000
#endif
+#ifndef GRCAN_SAMPLING_POINT
+#define GRCAN_SAMPLING_POINT 80
+#endif
+
/* Uncomment for debug output */
/****************** DEBUG Definitions ********************/
#define DBG_IOCTRL 1
@@ -97,9 +104,10 @@
#define DBG_RX 4
#define DEBUG_FLAGS (DBG_IOCTRL | DBG_RX | DBG_TX )
-/*#define DEBUG
-#define DEBUGFUNCS*/
-
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
#include <debug_defs.h>
/*********************************************************/
@@ -250,7 +258,7 @@ static void grcan_interrupt(struct grcan_priv *pDev);
#ifdef GRCAN_REG_BYPASS_CACHE
#define READ_REG(address) _grcan_read_nocache((unsigned int)(address))
#else
-#define READ_REG(address) (*(unsigned int *)(address))
+#define READ_REG(address) (*(volatile unsigned int *)(address))
#endif
#ifdef GRCAN_DMA_BYPASS_CACHE
@@ -266,8 +274,8 @@ static unsigned char __inline__ _grcan_read_nocache_byte(unsigned int address)
return tmp;
}
#else
-#define READ_DMA_WORD(address) (*(unsigned int *)(address))
-#define READ_DMA_BYTE(address) (*(unsigned char *)(address))
+#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
+#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
#endif
#if defined(GRCAN_REG_BYPASS_CACHE) || defined(GRCAN_DMA_BYPASS_CACHE)
@@ -293,6 +301,8 @@ static void __inline__ grcan_hw_reset(struct grcan_regs *regs)
static rtems_device_driver grcan_start(struct grcan_priv *pDev)
{
unsigned int tmp;
+ IRQ_GLOBAL_PREPARE(oldLevel);
+
FUNCDBG();
/* Check that memory has been allocated successfully */
@@ -335,11 +345,11 @@ static rtems_device_driver grcan_start(struct grcan_priv *pDev)
pDev->regs->imr = 0x1601f;
/* Enable routing of the IRQs */
- IRQ_GLOBAL_DISABLE();
+ IRQ_GLOBAL_DISABLE(oldLevel);
IRQ_UNMASK(pDev->irq+GRCAN_IRQ_TXSYNC);
IRQ_UNMASK(pDev->irq+GRCAN_IRQ_RXSYNC);
IRQ_UNMASK(pDev->irq+GRCAN_IRQ_IRQ);
- IRQ_GLOBAL_ENABLE();
+ IRQ_GLOBAL_ENABLE(oldLevel);
/* Reset some software data */
/*pDev->txerror = 0;
@@ -507,13 +517,121 @@ static int grcan_hw_tx_ongoing(struct grcan_regs *regs)
return READ_REG(&regs->tx0ctrl) & GRCAN_TXCTRL_ONGOING;
};
+
+#define MIN_TSEG1 1
+#define MIN_TSEG2 2
+#define MAX_TSEG1 14
+#define MAX_TSEG2 8
+
static int grcan_calc_timing(
unsigned int baud, /* The requested BAUD to calculate timing for */
unsigned int core_hz, /* Frequency in Hz of GRCAN Core */
+ unsigned int sampl_pt,
struct grcan_timing *timing /* result is placed here */
)
{
- return -1; /* not implemented yet */
+ int best_error = 1000000000;
+ int error;
+ int best_tseg=0, best_brp=0, best_rate=0, brp=0;
+ int tseg=0, tseg1=0, tseg2=0;
+ int sjw = 1;
+
+ /* Default to 90% */
+ if ( (sampl_pt < 50) || (sampl_pt>99) ){
+ sampl_pt = GRCAN_SAMPLING_POINT;
+ }
+
+ if ( (baud<5000) || (baud>1000000) ){
+ /* invalid speed mode */
+ return -1;
+ }
+
+ /* find best match, return -2 if no good reg
+ * combination is available for this frequency
+ */
+
+ /* some heuristic specials */
+ if (baud > ((1000000 + 500000) / 2))
+ sampl_pt = 75;
+
+ if (baud < ((12500 + 10000) / 2))
+ sampl_pt = 75;
+
+ /* tseg even = round down, odd = round up */
+ for (tseg = (MIN_TSEG1 + MIN_TSEG2 + 2) * 2;
+ tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
+ tseg++)
+ {
+ brp = core_hz / ((1 + tseg / 2) * baud) + tseg % 2;
+ if ((brp <= 0) ||
+ ( (brp > 256*1) && (brp <= 256*2) && (brp&0x1) ) ||
+ ( (brp > 256*2) && (brp <= 256*4) && (brp&0x3) ) ||
+ ( (brp > 256*4) && (brp <= 256*8) && (brp&0x7) ) ||
+ (brp > 256*8)
+ )
+ continue;
+
+ error = baud - core_hz / (brp * (1 + tseg / 2));
+ if (error < 0)
+ {
+ error = -error;
+ }
+
+ if (error <= best_error)
+ {
+ best_error = error;
+ best_tseg = tseg/2;
+ best_brp = brp-1;
+ best_rate = core_hz/(brp*(1+tseg/2));
+ }
+ }
+
+ if (best_error && (baud / best_error < 10))
+ {
+ return -2;
+ }else if ( !timing )
+ return 0; /* nothing to store result in, but a valid bitrate can be calculated */
+
+ tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
+
+ if (tseg2 < MIN_TSEG2)
+ {
+ tseg2 = MIN_TSEG2;
+ }
+
+ if (tseg2 > MAX_TSEG2)
+ {
+ tseg2 = MAX_TSEG2;
+ }
+
+ tseg1 = best_tseg - tseg2 - 2;
+
+ if (tseg1 > MAX_TSEG1)
+ {
+ tseg1 = MAX_TSEG1;
+ tseg2 = best_tseg - tseg1 - 2;
+ }
+
+ /* Get scaler and BRP from pseudo BRP */
+ if ( best_brp <= 256 ){
+ timing->scaler = best_brp;
+ timing->bpr = 0;
+ }else if ( best_brp <= 256*2 ){
+ timing->scaler = ((best_brp+1)>>1) -1;
+ timing->bpr = 1;
+ }else if ( best_brp <= 256*4 ){
+ timing->scaler = ((best_brp+1)>>2) -1;
+ timing->bpr = 2;
+ }else{
+ timing->scaler = ((best_brp+1)>>3) -1;
+ timing->bpr = 3;
+ }
+
+ timing->ps1 = tseg1+1;
+ timing->ps2 = tseg2;
+ timing->rsj = sjw;
+
+ return 0;
}
static unsigned int grcan_hw_read_try(
@@ -663,7 +781,6 @@ static unsigned int grcan_hw_write_try(
i=0;
while( (grcan_hw_tx_ongoing(regs)) && i<1000 ){
i++;
- printk("ongoing tx\n");
}
regs->tx0wr = (unsigned int)dest - addr; /* Update write pointer */
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE; /* ENABLE_TX_CHANNEL */
@@ -678,9 +795,16 @@ static int grcan_wait_rxdata(
unsigned int wp, rp, size, irq;
unsigned int irq_trunk, dataavail;
int wait;
+ IRQ_GLOBAL_PREPARE(oldLevel);
FUNCDBG();
-
+
+ /*** block until receive IRQ received
+ * Set up a valid IRQ point so that an IRQ is received
+ * when one or more messages are received
+ */
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
size = READ_REG(&pDev->regs->rx0size);
rp = READ_REG(&pDev->regs->rx0rd);
wp = READ_REG(&pDev->regs->rx0wr);
@@ -692,12 +816,6 @@ static int grcan_wait_rxdata(
irq_trunk = irq-size;
}else
irq_trunk = irq;
-
- /*** block until receive IRQ received
- * Set up a valid IRQ point so that an IRQ is received
- * when one or more messages are received
- */
- IRQ_GLOBAL_DISABLE();
/* init IRQ HW */
pDev->regs->rx0irq = irq_trunk;
@@ -718,7 +836,7 @@ static int grcan_wait_rxdata(
/* enough message has been received, abort sleep - don't unmask interrupt */
wait=0;
}
- IRQ_GLOBAL_ENABLE();
+ IRQ_GLOBAL_ENABLE(oldLevel);
/* Wait for IRQ to fire only if has been triggered */
if ( wait ){
@@ -744,14 +862,17 @@ static int grcan_wait_txspace(
int wait;
unsigned int irq, rp, wp, size, space_left;
unsigned int irq_trunk;
+ IRQ_GLOBAL_PREPARE(oldLevel);
DBGC(DBG_TX,"\n");
/*FUNCDBG();*/
+ IRQ_GLOBAL_DISABLE(oldLevel);
+
+ /*pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;*/
+
size = READ_REG(&pDev->regs->tx0size);
wp = READ_REG(&pDev->regs->tx0wr);
-
- IRQ_GLOBAL_DISABLE();
rp = READ_REG(&pDev->regs->tx0rd);
@@ -788,11 +909,11 @@ static int grcan_wait_txspace(
/* There are enough room in buffer, abort wait - don't unmask interrupt */
wait=0;
}
- IRQ_GLOBAL_ENABLE();
+ IRQ_GLOBAL_ENABLE(oldLevel);
/* Wait for IRQ to fire only if it has been triggered */
if ( wait ){
- if ( rtems_semaphore_obtain(pDev->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) ==
+ if ( rtems_semaphore_obtain(pDev->tx_sem, RTEMS_WAIT, 100) ==
RTEMS_UNSATISFIED ){
/* Device driver has flushed us, this may be due to another thread has
* closed the device, this is to avoid deadlock */
@@ -808,6 +929,7 @@ static int grcan_tx_flush(struct grcan_priv *pDev)
{
int wait;
unsigned int rp, wp;
+ IRQ_GLOBAL_PREPARE(oldLevel);
FUNCDBG();
/* loop until all data in circular buffer has been read by hw.
@@ -817,7 +939,7 @@ static int grcan_tx_flush(struct grcan_priv *pDev)
*/
while ( (wp=READ_REG(&pDev->regs->tx0wr)) != (rp=READ_REG(&pDev->regs->tx0rd)) ) {
/* Wait for TX empty IRQ */
- IRQ_GLOBAL_DISABLE();
+ IRQ_GLOBAL_DISABLE(oldLevel);
/* Clear pending TXEmpty IRQ */
pDev->regs->picr = GRCAN_TXEMPTY_IRQ;
@@ -829,7 +951,7 @@ static int grcan_tx_flush(struct grcan_priv *pDev)
/* TX fifo is empty */
wait = 0;
}
- IRQ_GLOBAL_ENABLE();
+ IRQ_GLOBAL_ENABLE(oldLevel);
if ( !wait )
break;
@@ -932,6 +1054,7 @@ static rtems_device_driver grcan_initialize(
rtems_status_code status;
char fs_name[20];
unsigned int sys_freq_hz;
+ unsigned int deviceid = GAISLER_GRHCAN;
printk("grcan_initialize()\n\r");
@@ -939,10 +1062,16 @@ static rtems_device_driver grcan_initialize(
/* find GRCAN cores */
if ( !grcan_cores ) {
- grcan_core_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_GRHCAN);
+ grcan_core_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,deviceid);
+ if ( grcan_core_cnt < 1 ){
+ deviceid = GAISLER_GRCAN;
+ grcan_core_cnt = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,deviceid);
+ if ( grcan_core_cnt < 1 ) {
+ DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt);
+ return RTEMS_UNSATISFIED;
+ }
+ }
DBG("GRCAN: Using AMBA Plug&Play, found %d cores\n",grcan_core_cnt);
- if ( grcan_core_cnt < 1 )
- return RTEMS_UNSATISFIED;
}
#ifdef GRCAN_MAX_CORENR
@@ -1003,7 +1132,7 @@ static rtems_device_driver grcan_initialize(
/* Find core address & IRQ */
if ( !grcan_cores ) {
- amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_GRHCAN,&dev,minor);
+ amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,deviceid,&dev,minor);
pDev->irq = dev.irq;
pDev->regs = (struct grcan_regs *)dev.start;
}else{
@@ -1011,7 +1140,6 @@ static rtems_device_driver grcan_initialize(
pDev->regs = (struct grcan_regs *)grcan_cores[minor].base_address;
}
- DBG("Registering GRCAN core at [0x%x] irq %d, minor %d as %s\n",pDev->regs,pDev->irq,minor,fs_name);
printk("Registering GRCAN core at [0x%x] irq %d, minor %d as %s\n\r",pDev->regs,pDev->irq,minor,fs_name);
status = rtems_io_register_name(fs_name, major, 0);
@@ -1121,7 +1249,7 @@ static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_dev
pDev->sfilter.code = 0x00000000;
/* Calculate default timing register values */
- grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,&pDev->config.timing);
+ grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
if ( grcan_alloc_buffers(pDev,1,1) ) {
ret=RTEMS_NO_MEMORY;
@@ -1333,6 +1461,7 @@ static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_de
rtems_device_driver status;
struct grcan_stats *stats;
struct grcan_filter *filter;
+ IRQ_GLOBAL_PREPARE(oldLevel);
FUNCDBG();
@@ -1448,9 +1577,9 @@ static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_de
break;
case GRCAN_IOC_CLR_STATS:
- IRQ_GLOBAL_DISABLE();
+ IRQ_GLOBAL_DISABLE(oldLevel);
memset(&pDev->stats,0,sizeof(struct grcan_stats));
- IRQ_GLOBAL_ENABLE();
+ IRQ_GLOBAL_ENABLE(oldLevel);
break;
case GRCAN_IOC_SET_SPEED:
@@ -1461,7 +1590,7 @@ static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_de
/* get speed rate from argument */
speed = (unsigned int)ioarg->buffer;
- ret = grcan_calc_timing(pDev->corefreq_hz,speed,&timing);
+ ret = grcan_calc_timing(speed,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&timing);
if ( ret )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -1537,7 +1666,7 @@ static rtems_isr grcan_interrupt_handler(rtems_vector_number v)
{
int minor=0;
while ( minor < grcan_core_cnt ){
- if ( grcans[minor].irq == (v+0x10) ){
+ if ( (grcans[minor].irq+0x10) == v ){
grcan_interrupt(&grcans[minor]);
break;
}
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c b/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c
index 9dd9e55f20..96755547fb 100644
--- a/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c
+++ b/c/src/lib/libbsp/sparc/shared/can/grcan_rasta.c
@@ -2,7 +2,7 @@
#include <rasta.h>
/* PCI frequency */
-#define SYS_FREQ_HZ 33000000
+#define SYS_FREQ_HZ 30000000
/*#define USE_AT697_RAM 1 */
@@ -29,8 +29,9 @@ static inline unsigned int memarea_to_hw(unsigned int addr) {
#define IRQ_UNMASK(irqno)
#define IRQ_MASK(irqno)
-#define IRQ_GLOBAL_DISABLE() sparc_disable_interrupts()
-#define IRQ_GLOBAL_ENABLE() sparc_enable_interrupts()
+#define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
#define GRCAN_REG_INT(handler,irqno,arg) \
if ( grcan_rasta_int_reg ) \
diff --git a/c/src/lib/libbsp/sparc/shared/include/ambapp.h b/c/src/lib/libbsp/sparc/shared/include/ambapp.h
index e63648d13c..a26bfd4b83 100644
--- a/c/src/lib/libbsp/sparc/shared/include/ambapp.h
+++ b/c/src/lib/libbsp/sparc/shared/include/ambapp.h
@@ -58,8 +58,12 @@ extern "C" {
#define GAISLER_ETHMAC 0x1D
#define GAISLER_SPACEWIRE 0x1f
#define GAISLER_AHB2AHB 0x20
-#define GAISLER_GRHCAN 0x34
+#define GAISLER_I2CMST 0x28
+#define GAISLER_GRSPW2 0x29
+#define GAISLER_GRCAN 0x34
+#define GAISLER_GRHCAN 0x3d
#define GAISLER_GRFIFO 0x35
+#define GAISLER_GRADCDAC 0x36
#define GAISLER_GRPULSE 0x37
#define GAISLER_GRTIMER 0x38
#define GAISLER_FTAHBRAM 0x50