summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2007-10-11 12:56:09 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2007-10-11 12:56:09 +0000
commit0743eaed1c83e9eb73986e15e9f7e8dc9c297a92 (patch)
tree4b991c8d5e96e9196d15fa52f05373b3bad45fa0 /c/src/lib/libbsp/sparc
parent2007-10-11 Daniel Hellstrom <daniel@gaisler.com> (diff)
downloadrtems-0743eaed1c83e9eb73986e15e9f7e8dc9c297a92.tar.bz2
2007-10-11 Daniel Hellstrom <daniel@gaisler.com>
* Makefile.am, shared/can/occan.c, shared/include/ambapp.h: Add initial i2c and update OC-CAN support. * shared/i2c/i2cmst.c, shared/include/i2cmst.h: New files.
Diffstat (limited to 'c/src/lib/libbsp/sparc')
-rw-r--r--c/src/lib/libbsp/sparc/ChangeLog6
-rw-r--r--c/src/lib/libbsp/sparc/Makefile.am4
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/occan.c30
-rw-r--r--c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c358
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/ambapp.h2
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/i2cmst.h77
6 files changed, 456 insertions, 21 deletions
diff --git a/c/src/lib/libbsp/sparc/ChangeLog b/c/src/lib/libbsp/sparc/ChangeLog
index 569854d8c8..cb4e39f6b3 100644
--- a/c/src/lib/libbsp/sparc/ChangeLog
+++ b/c/src/lib/libbsp/sparc/ChangeLog
@@ -1,3 +1,9 @@
+2007-10-11 Daniel Hellstrom <daniel@gaisler.com>
+
+ * Makefile.am, shared/can/occan.c, shared/include/ambapp.h: Add initial
+ i2c and update OC-CAN support.
+ * shared/i2c/i2cmst.c, shared/include/i2cmst.h: New files.
+
2007-09-21 Daniel Hellstrom <daniel@gaisler.com>
* shared/can/occan.c: Fix warning on Diab compiler.
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am
index 3f2bfff9a4..8081d61609 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -59,5 +59,9 @@ EXTRA_DIST += shared/include/b1553brm.h
EXTRA_DIST += shared/include/b1553brm_pci.h
EXTRA_DIST += shared/include/b1553brm_rasta.h
+# I2C-master (I2CMST)
+EXTRA_DIST += shared/i2c/i2cmst.c
+EXTRA_DIST += shared/include/i2cmst.h
+
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/lib/libbsp/sparc/shared/can/occan.c b/c/src/lib/libbsp/sparc/shared/can/occan.c
index f3318165a8..66e27f2a4b 100644
--- a/c/src/lib/libbsp/sparc/shared/can/occan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/occan.c
@@ -198,8 +198,8 @@ typedef struct {
} pelican_regs;
#endif
-#define MAX_TSEG1 7
-#define MAX_TSEG2 15
+#define MAX_TSEG2 7
+#define MAX_TSEG1 15
#if 0
typedef struct {
@@ -728,16 +728,13 @@ static void occan_stat_print(occan_stats *stats){
}
#endif
-/* This function calculates BTR0 BTR1 values for a given bitrate.
- * Heavily based on mgt_mscan_bitrate() from peak driver, which
- * in turn is based on work by Arnaud Westenberg.
+/* This function calculates BTR0 and BTR1 values for a given bitrate.
*
* Set communication parameters.
- * baud rate in Hz
- * input clock frequency of can core in Hz (system frequency)
- * sjw synchronization jump width (0-3) prescaled clock cycles
- * sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3)
- * ratio
+ * \param clock_hz OC_CAN Core frequency in Hz.
+ * \param rate Requested baud rate in bits/second.
+ * \param result Pointer to where resulting BTRs will be stored.
+ * \return zero if successful to calculate a baud rate.
*/
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result){
int best_error = 1000000000;
@@ -748,7 +745,7 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_
int clock = clock_hz / 2;
int sampl_pt = 90;
- if ( (rate<10000) || (rate>1000000) ){
+ if ( (rate<5000) || (rate>1000000) ){
/* invalid speed mode */
return -1;
}
@@ -816,12 +813,7 @@ static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_
tseg1 = MAX_TSEG1;
tseg2 = best_tseg - tseg1 - 2;
}
-/*
- result->sjw = sjw;
- result->brp = best_brp;
- result->tseg1 = tseg1;
- result->tseg2 = tseg2;
-*/
+
result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
@@ -834,10 +826,6 @@ static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing){
priv->regs->bustim0 = timing->btr0;
priv->regs->bustim1 = timing->btr1;
- /*
- priv->regs->bustim0 = (timing->sjw<<OCCAN_BUSTIM_SJW_BIT) | (timing->brp&OCCAN_BUSTIM_BRP);
- priv->regs->bustim1 = (timing->sam<<7) | (timing->tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | timing->tseg1;
- */
return 0;
}
diff --git a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
new file mode 100644
index 0000000000..2a59d32879
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c
@@ -0,0 +1,358 @@
+/*
+ * Driver for GRLIB port of OpenCores I2C-master
+ *
+ * COPYRIGHT (c) 2007 Gaisler Research
+ * based on the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH.
+ *
+ * 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.
+ *
+ * This file contains the driver and initialization code
+ *
+ * 2007-09-27: First version of driver (jan@gaisler.com)
+ */
+
+
+#include <bsp.h>
+#include <i2cmst.h>
+#include <ambapp.h>
+#include <rtems/libi2c.h>
+
+/* Enable debug printks? */
+/* #define DEBUG */
+
+/* Default to 40 MHz system clock? */
+/*
+ #ifndef SYS_FREQ_kHZ
+ #define SYS_FREQ_kHZ 40000
+ #endif
+*/
+
+
+/* Calculates the scaler value for 100 kHz operation */
+static int gr_i2cmst_calc_scaler(int sysfreq)
+{
+ return sysfreq/500 - 1;
+}
+
+/* Wait for the current transfer to end */
+static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts)
+{
+ uint32_t tout = 0;
+ int current_sts;
+#if defined(DEBUG)
+ printk("(gr_i2cmst_wait called...");
+#endif
+
+ do {
+ if (tout++ > 1000000) {
+ return RTEMS_TIMEOUT;
+ }
+ } while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP);
+
+ current_sts = prv_ptr->reg_ptr->cmdsts & ~GRI2C_STS_IF & ~GRI2C_STS_BUSY;
+
+ if (current_sts != expected_sts) {
+#if defined(DEBUG)
+ if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) {
+ printk("Transfer NAKed..");
+ }
+ if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) {
+ printk("arbitration lost..");
+ }
+ if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) {
+ printk("transfer still in progress, huh?..");
+ }
+ printk("exited with IO error..)");
+#endif
+ return RTEMS_IO_ERROR;
+ }
+
+#if defined(DEBUG)
+ printk("exited...)");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+/* Initialize hardware core */
+static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl)
+{
+ gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+#if defined(DEBUG)
+ printk("gr_i2cmst_init called...");
+#endif
+
+ /* Disable core before changing prescale register */
+ prv_ptr->reg_ptr->ctrl = 0;
+
+ /* Calculate and set prescale value */
+ prv_ptr->reg_ptr->prescl = gr_i2cmst_calc_scaler(prv_ptr->sysfreq);
+
+ /* Enable core, interrupts are not enabled */
+ prv_ptr->reg_ptr->ctrl = GRI2C_CTRL_EN;
+
+ /* Clear possible START condition */
+ prv_ptr->sendstart = 0;
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code gr_i2cmst_send_start(rtems_libi2c_bus_t *bushdl)
+{
+ gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+#if defined(DEBUG)
+ printk("gr_i2cmst_send_start called...");
+#endif
+
+ /* The OC I2C core does not work with stand alone START events,
+ instead the event is buffered */
+ prv_ptr->sendstart = GRI2C_CMD_STA;
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code gr_i2cmst_send_stop(rtems_libi2c_bus_t *bushdl)
+{
+ gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+#if defined(DEBUG)
+ printk("gr_i2cmst_send_stop called...");
+#endif
+
+ prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO;
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl,
+ uint32_t addr, int rw)
+{
+ gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ uint8_t addr_byte;
+ rtems_status_code rc;
+#if defined(DEBUG)
+ printk("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...",
+ addr, rw);
+#endif
+
+ /* Check if long address is needed */
+ if (addr > 0x7f) {
+ addr_byte = ((addr >> 7) & 0x06) | (rw ? 1 : 0);
+
+ prv_ptr->reg_ptr->tdrd = addr_byte;
+ prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
+ prv_ptr->sendstart = 0;
+
+ /* Wait for transfer to complete */
+ rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("exited with error\n");
+#endif
+ return -rc;
+ }
+ }
+
+ /* For 10-bit adresses the last byte should only be written for a
+ write operation */
+ rc = RTEMS_SUCCESSFUL;
+ if (addr <= 0x7f || rw == 0) {
+ addr_byte = (addr << 1) | (rw ? 1 : 0);
+
+ prv_ptr->reg_ptr->tdrd = addr_byte;
+ prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
+ prv_ptr->sendstart = 0;
+
+ /* Wait for transfer to complete */
+ rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("exited with error\n");
+#endif
+ return -rc;
+ }
+ }
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return rc;
+}
+
+
+static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl,
+ unsigned char *bytes, int nbytes)
+{
+ gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ unsigned char *buf = bytes;
+ rtems_status_code rc;
+ unsigned char expected_sts = GRI2C_STATUS_IDLE;
+#if defined(DEBUG)
+ printk("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes);
+#endif
+
+ while (nbytes-- > 0) {
+ if (nbytes == 0) {
+ /* Respond with NAK to end sequential read */
+ prv_ptr->reg_ptr->cmdsts = (GRI2C_CMD_RD | GRI2C_CMD_ACK |
+ prv_ptr->sendstart);
+ expected_sts = GRI2C_STS_RXACK;
+ } else {
+ prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_RD | prv_ptr->sendstart;
+ }
+ prv_ptr->sendstart = 0;
+ /* Wait until end of transfer */
+ rc = gr_i2cmst_wait(prv_ptr, expected_sts);
+ if (rc != RTEMS_SUCCESSFUL) {
+ return -rc;
+#if defined(DEBUG)
+ printk("exited with error\n");
+#endif
+ }
+ *buf++ = prv_ptr->reg_ptr->tdrd;
+ }
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return buf - bytes;
+}
+
+static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl,
+ unsigned char *bytes, int nbytes)
+{
+ gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv);
+ unsigned char *buf = bytes;
+ rtems_status_code rc;
+#if defined(DEBUG)
+ printk("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes);
+#endif
+
+ while (nbytes-- > 0) {
+#if defined(DEBUG)
+ printk("writing byte 0x%02X...", *buf);
+#endif
+ prv_ptr->reg_ptr->tdrd = *buf++;
+ prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart;
+ prv_ptr->sendstart = 0;
+
+ /* Wait for transfer to complete */
+ rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE);
+
+ if (rc != RTEMS_SUCCESSFUL) {
+#if defined(DEBUG)
+ printk("exited with error\n");
+#endif
+ return -rc;
+ }
+ }
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return buf - bytes;
+}
+
+static rtems_libi2c_bus_ops_t gr_i2cmst_ops = {
+ init: gr_i2cmst_init,
+ send_start: gr_i2cmst_send_start,
+ send_stop: gr_i2cmst_send_stop,
+ send_addr: gr_i2cmst_send_addr,
+ read_bytes: gr_i2cmst_read_bytes,
+ write_bytes: gr_i2cmst_write_bytes,
+};
+
+
+static gr_i2cmst_desc_t gr_i2cmst_desc = {
+ { /* rtems_libi2c_bus_t */
+ ops : &gr_i2cmst_ops,
+ size : sizeof(gr_i2cmst_ops),
+ },
+ { /* gr_i2cmst_prv_t, private data */
+ reg_ptr : NULL,
+ sysfreq : 40000,
+ }
+
+};
+
+/* Scans for I2CMST core and initalizes i2c library */
+rtems_status_code leon_register_i2c(amba_confarea_type *abus)
+{
+#if defined(DEBUG)
+ printk("leon_register_i2c called...");
+#endif
+
+ int rc;
+ int device_found = 0;
+ amba_apb_device apbi2cmst;
+
+ /* Scan AMBA bus for I2CMST core */
+ device_found = amba_find_apbslv(abus, VENDOR_GAISLER, GAISLER_I2CMST,
+ &apbi2cmst);
+
+ if (device_found == 1) {
+
+ /* Initialize i2c library */
+ rc = rtems_libi2c_initialize();
+ if (rc < 0) {
+#if defined(DEBUG)
+ printk("rtems_libi2x_initialize failed, exiting...\n");
+#endif
+ return rc;
+ }
+
+ gr_i2cmst_desc.prv.reg_ptr = (gr_i2cmst_regs_t *)apbi2cmst.start;
+
+ /* Detect system frequency, same as in apbuart_initialize */
+#ifndef SYS_FREQ_kHZ
+#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(abus,VENDOR_GAISLER,
+ GAISLER_GPTIMER,&gptimer) == 1 ) {
+ tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
+ gr_i2cmst_desc.prv.sysfreq = (tregs->scaler_reload+1)*1000;
+ } else {
+ gr_i2cmst_desc.prv.sysfreq = 40000; /* Default to 40MHz */
+ }
+ }
+#elif defined(LEON2)
+ /* LEON2: use hardcoded address to get to timer */
+ {
+ LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
+ gr_i2cmst_desc.prv.sysfreq = (regs->Scaler_Reload+1)*1000;
+ }
+#else
+#error CPU not supported for I2CMST driver */
+#endif
+#else
+ /* Use hardcoded frequency */
+ gr_i2cmst_desc.prv.sysfreq = SYS_FREQ_kHZ;
+#endif
+
+ rc = rtems_libi2c_register_bus("/dev/i2c1", &gr_i2cmst_desc.bus_desc);
+ if (rc < 0) {
+#if defined(DEBUG)
+ printk("rtems_libi2c_register_bus failed, exiting..\n");
+#endif
+ return -rc;
+ }
+ }
+
+#if defined(DEBUG)
+ printk("exited\n");
+#endif
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/include/ambapp.h b/c/src/lib/libbsp/sparc/shared/include/ambapp.h
index e63648d13c..bb2066c4da 100644
--- a/c/src/lib/libbsp/sparc/shared/include/ambapp.h
+++ b/c/src/lib/libbsp/sparc/shared/include/ambapp.h
@@ -58,6 +58,8 @@ extern "C" {
#define GAISLER_ETHMAC 0x1D
#define GAISLER_SPACEWIRE 0x1f
#define GAISLER_AHB2AHB 0x20
+#define GAISLER_I2CMST 0x28
+#define GAISLER_GRSPW2 0x29
#define GAISLER_GRHCAN 0x34
#define GAISLER_GRFIFO 0x35
#define GAISLER_GRPULSE 0x37
diff --git a/c/src/lib/libbsp/sparc/shared/include/i2cmst.h b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
new file mode 100644
index 0000000000..63942a45e6
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/i2cmst.h
@@ -0,0 +1,77 @@
+/*
+ * Driver for GRLIB port of OpenCores I2C-master
+ *
+ * COPYRIGHT (c) 2007 Gaisler Research
+ * with parts from the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH.
+ *
+ * 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.
+ *
+ * This file contains the driver declarations
+ */
+#ifndef _I2CMST_H
+#define _I2CMST_H
+
+#include <rtems/libi2c.h>
+#include <ambapp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* I2C-master operational registers */
+
+typedef struct gr_i2cmst_regs {
+ volatile unsigned int prescl; /* Prescale register */
+ volatile unsigned int ctrl; /* Control register */
+ volatile unsigned int tdrd; /* Transmit and Receive registers */
+ volatile unsigned int cmdsts; /* Command and Status registers */
+} gr_i2cmst_regs_t;
+
+/* Control (CTRL) register */
+#define GRI2C_CTRL_EN 0x00000080 /* Enable core */
+#define GRI2C_CTRL_IEN 0x00000040 /* Interrupt enable */
+
+/* Command (CMD) register */
+#define GRI2C_CMD_STA 0x00000080 /* Generate START condition */
+#define GRI2C_CMD_STO 0x00000040 /* Generate STOP condition */
+#define GRI2C_CMD_RD 0x00000020 /* Read from slave */
+#define GRI2C_CMD_WR 0x00000010 /* Write to slave */
+#define GRI2C_CMD_ACK 0x00000008 /* Acknowledge */
+#define GRI2C_CMD_IACK 0x00000001 /* Interrupt acknowledge */
+
+/* Status (STS) register */
+#define GRI2C_STS_RXACK 0x00000080 /* Receive acknowledge */
+#define GRI2C_STS_BUSY 0x00000040 /* I2C-bus busy */
+#define GRI2C_STS_AL 0x00000020 /* Arbitration lost */
+#define GRI2C_STS_TIP 0x00000002 /* Transfer in progress */
+#define GRI2C_STS_IF 0x00000001 /* Interrupt flag */
+
+#define GRI2C_STATUS_IDLE 0x00000000
+
+/* The OC I2C core will perform a write after a start unless the RD bit
+ in the command register has been set. Since the rtems framework has
+ a send_start function we buffer that command and use it when the first
+ data is written. The START is buffered in the sendstart member below */
+typedef struct gr_i2cmst_prv {
+ gr_i2cmst_regs_t *reg_ptr;
+ unsigned int sysfreq; /* System clock frequency in kHz */
+ unsigned char sendstart; /* START events are buffered here */
+ /* rtems_irq_number irq_number; */
+ /* rtems_id irq_sema_id; */
+} gr_i2cmst_prv_t;
+
+typedef struct gr_i2cmst_desc {
+ rtems_libi2c_bus_t bus_desc;
+ gr_i2cmst_prv_t prv;
+} gr_i2cmst_desc_t;
+
+/* Scans for I2CMST core and initalizes i2c library */
+rtems_status_code leon_register_i2c(amba_confarea_type *abus);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _I2CMST_H */