summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/slink/grslink.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/slink/grslink.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/slink/grslink.c661
1 files changed, 0 insertions, 661 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/slink/grslink.c b/c/src/lib/libbsp/sparc/shared/slink/grslink.c
deleted file mode 100644
index 22a29546d0..0000000000
--- a/c/src/lib/libbsp/sparc/shared/slink/grslink.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * This file contains the RTEMS GRSLINK SLINK master driver
- *
- * COPYRIGHT (c) 2009.
- * Cobham Gaisler AB.
- *
- * 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.
- *
- * Comments concerning current driver implementation:
- *
- * The SLINK specification says that there are three IO cards that are capable
- * of transmitting data. But these IO cards can have the address range 0 to 3,
- * and an 'For information only' comment explains that the current
- * implementation has receive buffers for ".. x 4 (IO cards)".
- * Because of this the driver has four queues, one for each IO card 0 - 3.
- * When the addressing convention used for the IO cards is known, the number of
- * queues may be lowered to three.
- *
- */
-
-#include <stdlib.h>
-
-#include <bsp.h>
-#include <bsp/grslink.h>
-#include <ambapp.h>
-
-#ifndef GAISLER_SLINK
-#define GAISLER_SLINK 0x02F
-#endif
-
-/* Enable debug output? */
-/* #define DEBUG */
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* Bits and fields in SLINK transmit word */
-#define SLINK_RW (1 << 23)
-#define SLINK_CHAN_POS 16
-
-/* Local types */
-typedef struct {
- volatile unsigned int clockscale;
- volatile unsigned int ctrl;
- volatile unsigned int nullwrd;
- volatile unsigned int sts;
- volatile unsigned int msk;
- volatile unsigned int abase;
- volatile unsigned int bbase;
- volatile unsigned int td;
- volatile unsigned int rd;
-} SLINK_regs;
-
-typedef struct {
- char readstat; /* Status of READ operation */
- char seqstat; /* Status of SEQUENCE operation */
- unsigned char scnt; /* Number of SEQUENCE words transferred */
-} SLINK_status;
-
-typedef struct {
- int size;
- unsigned int *buf;
- unsigned int *first;
- unsigned int *last;
- unsigned int *max;
- int full;
-} SLINK_queue;
-
-typedef struct {
- SLINK_regs *reg; /* Pointer to core registers */
- SLINK_status *status; /* Driver status information */
- void (*slink_irq_handler)(int); /* Handler for INTERRUPT */
- void (*slink_seq_change)(int); /* Callback on SEQUENCE change */
- int rword; /* Placeholder for READ response */
- rtems_id read_sem; /* Semaphore for blocking SLINK_read */
- SLINK_queue *queues; /* Receive queues */
-#ifdef SLINK_COLLECT_STATISTICS
- SLINK_stats *stats; /* Core statistics, optional */
-#endif
-} SLINK_cfg;
-
-
-static SLINK_cfg *cfg = NULL;
-
-/**** SLINK driver queues for unsolicited and INTERRUPT requests ****/
-
-/* Function: SLINK_createqueues
- * Arguments: size: Number of elements in each queue
- * Returns: 0 on success, -1 on failure
- * Description: Creates SLINK_NUMQUEUES queues, one for each IO card
- * that can send data. The pointers to the queues is saved in the driver
- * config structure.
- */
-static int SLINK_createqueues(int size)
-{
- SLINK_queue *q;
- int i, j;
-
- if ((q = malloc(SLINK_NUMQUEUES*sizeof(SLINK_queue))) == NULL)
- goto slink_qiniterr1;
-
- for (i = 0; i < SLINK_NUMQUEUES; i++) {
- q[i].size = size;
- if ((q[i].buf = malloc(size*sizeof(int))) == NULL)
- goto slink_qiniterr2;
- q[i].first = q[i].last = q[i].buf;
- q[i].max = q[i].buf + (size-1);
- q[i].full = 0;
- }
-
- cfg->queues = q;
-
- return 0;
-
- slink_qiniterr2:
- for (j = 0; j < i; j++)
- free(q[i].buf);
- free(q);
- slink_qiniterr1:
- return -1;
-}
-
-/*
- * Function: SLINK_destroyqueues
- * Arguments: None
- * Returns: Nothing
- * Description: Frees the memory occupied by the queues in cfg->queues
- */
-/*
- static void SLINK_destroyqueues(void)
- {
- int i;
-
- for(i = 0; i < SLINK_NUMQUEUES; i++)
- free(cfg->queues[i].buf);
-
- free(cfg->queues);
-}
-*/
-
-/*
- * Function: SLINK_enqueue
- * Arguments: Received SLINK word
- * Returns: Nothing
- * Description:
- */
-static void SLINK_enqueue(unsigned int slink_wrd)
-{
- SLINK_queue *ioq = cfg->queues + SLINK_WRD_CARDNUM(slink_wrd);
-
- if (!ioq->full && SLINK_WRD_CARDNUM(slink_wrd) < SLINK_NUMQUEUES) {
- *ioq->last = slink_wrd;
- ioq->last = (ioq->last >= ioq->max) ? ioq->buf : ioq->last+1;
- ioq->full = ioq->last == ioq->first;
- return;
- }
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->lostwords++;
-#endif
-}
-
-/**** SLINK driver helper functions ****/
-
-/*
- * Function: SLINK_getaddr
- * Arguments: amba_conf
- * base: assigned to base of core registers
- * irq: assigned to core irq lines
- * Returns: Base address and IRQ via arguments, 0 if core is found, else -1
- * Description: See above.
- */
-static int SLINK_getaddr(int *base, int *irq)
-{
- struct ambapp_apb_info c;
-
- if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_SLINK,&c) == 1) {
- *base = c.start;
- *irq = c.irq;
- return 0;
- }
- return -1;
-}
-
-/* Function: SLINK_calcscaler
- * Arguments: sysfreq: System frequency in Hz
- * Returns: Clock scaler register value
- * Description: Calculates value for SLINK clock scaler register to attain
- * a SLINK bus frequency as close to 6 MHz as possible. Please see the IP core
- * documentation for a description of how clock scaling is implemented.
- */
-static int SLINK_calcscaler(int sysfreq)
-{
- int fact = sysfreq / SLINK_FREQ_HZ;
- return ((fact/2-1) << 16) | (fact % 2 ? fact/2 : fact/2-1);
-}
-
-
-/*
- * Function: SLINK_getsysfreq
- * Arguments: None
- * Returns: System frequency in Hz, or 0 if system timer is not found.
- * Description: Looks at the timer to determine system frequency. Makes use
- * of AMBA Plug'n'Play.
- */
-static int SLINK_getsysfreq(void)
-{
- struct ambapp_apb_info t;
- struct gptimer_regs *tregs;
-
- if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_GPTIMER,&t)==1) {
- tregs = (struct gptimer_regs *)t.start;
- DBG("SLINK_getsysfreq returning %d\n",
- (tregs->scaler_reload+1)*1000*1000);
- return (tregs->scaler_reload+1)*1000*1000;
- }
- return 0;
-}
-
-/*
- * Function: SLINK_interrupt_handler
- * Arguments: v: not used
- * Returns: Nothing
- * Description: Interrupt handles checks RNE, SEQUENCE and error status
- * bits. Reads word from receive queue and distinguishes between INTERRUPT,
- * READ responses and SLAVE-WORD-SEND. When an INTERRUPT transfer is detected
- * the handler calls the user specified slink_irq_handler with the received
- * word. READ responses are saved and given to SLINK_read via a private
- * variable. SLAVE-WORD-SEND transfers are placed in the IO card's receive
- * queue.
- */
-static rtems_isr SLINK_interrupt_handler(rtems_vector_number v)
-{
- unsigned int sts;
- unsigned int wrd;
-
- /* Read all words from Receive queue */
- while ((sts = cfg->reg->sts) & SLINK_S_RNE) {
-
- /* Read first word in receive queue */
- wrd = cfg->reg->rd;
-
- /* Check channel value to determine action */
- switch (SLINK_WRD_CHAN(wrd)) {
- case 0: /* Interrupt */
- cfg->slink_irq_handler(wrd);
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->interrupts++;
-#endif
- break;
- case 3: /* Read response, if no active READ, fall-through */
- if (cfg->status->readstat == SLINK_ACTIVE) {
- rtems_semaphore_release(cfg->read_sem);
- cfg->status->readstat = SLINK_COMPLETED;
- cfg->rword = wrd;
- break;
- }
- default: /* Unsolicited request */
- SLINK_enqueue(wrd);
- break;
- }
- }
-
- /* Check sequence operation */
- if (sts & SLINK_S_SC) {
- /* SEQUENCE completed */
- cfg->status->seqstat = SLINK_COMPLETED;
- if (cfg->slink_seq_change)
- cfg->slink_seq_change(SLINK_COMPLETED);
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->seqcomp++;
-#endif
- } else if (sts & SLINK_S_SA) {
- /* SEQUENCE aborted */
- cfg->status->seqstat = SLINK_ABORTED;
- cfg->status->scnt = (sts >> SLINK_S_SI_POS);
- if (cfg->slink_seq_change)
- cfg->slink_seq_change(SLINK_ABORTED);
- }
-
- /* Check error conditions */
- if (sts & SLINK_S_PERR) {
- /*
- Parity error detected, set seqstat if there is an ongoing
- sequence so that the calling application can decide if the
- sequence should be aborted
- */
- if (cfg->status->seqstat == SLINK_ACTIVE) {
- cfg->status->seqstat = SLINK_PARERR;
- if (cfg->slink_seq_change)
- cfg->slink_seq_change(SLINK_PARERR);
- }
- /* Abort READ operation */
- if (cfg->status->readstat == SLINK_ACTIVE) {
- cfg->status->readstat = SLINK_PARERR;
- rtems_semaphore_release(cfg->read_sem);
- }
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->parerr++;
-#endif
- }
- if (sts & SLINK_S_AERR) {
- /* AMBA error response, sequence aborted */
- cfg->status->seqstat = SLINK_AMBAERR;
- cfg->status->scnt = sts >> SLINK_S_SI_POS;
- if (cfg->slink_seq_change)
- cfg->slink_seq_change(SLINK_AMBAERR);
- }
- if (sts & SLINK_S_ROV) {
- /* Receive overflow, abort any ongoing READ */
- if (cfg->status->readstat == SLINK_ACTIVE) {
- cfg->status->readstat = SLINK_ROV;
- rtems_semaphore_release(cfg->read_sem);
- }
-#ifdef SLINK_COLLECT_STATISICS
- cfg->status->recov++;
-#endif
- }
-
- /* Clear processed bits */
- cfg->reg->sts = sts;
-}
-
-/**** SLINK driver interface starts here ****/
-
-/* Function: SLINK_init
- * Arguments: nullwrd: NULL word
- * parity: Even (0) or Odd (1) parity
- * interrupt_trans_handler: Function that handles interrupt requests
- * sequence_callback: Callback on SEQUENCE status changes
- * qsize: Size of each receive queue
- * Returns: 0 on success, -1 on failure
- * Description: Initializes the SLINK core
- */
-int SLINK_init(unsigned int nullwrd, int parity, int qsize,
- void (*interrupt_trans_handler)(int),
- void (*sequence_callback)(int))
-{
- int base;
- int irq;
- rtems_status_code st;
-
- /* Allocate private config structure */
- if (cfg == NULL && (cfg = malloc(sizeof(SLINK_cfg))) == NULL) {
- DBG("SLINK_init: Could not allocate cfg structure\n");
- goto slink_initerr1;
- }
-
- /* Create simple binary semaphore for blocking SLINK_read */
- st = rtems_semaphore_create(rtems_build_name('S', 'L', 'R', '0'), 0,
- (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
- RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
- RTEMS_NO_PRIORITY_CEILING), 0,
- &cfg->read_sem);
- if (st != RTEMS_SUCCESSFUL) {
- DBG("SLINK_init: Could not create semaphore\n");
- goto slink_initerr1;
- }
-
- /* Initialize pointer to SLINK core registers and get IRQ line */
- if (SLINK_getaddr(&base, &irq) == -1) {
- DBG("SLINK_init: Could not find core\n");
- goto slink_initerr2;
- }
- cfg->reg = (SLINK_regs*)base;
-
- /* Allocate status structure and initialize members */
- if ((cfg->status = calloc(1, sizeof(SLINK_status))) == NULL) {
- DBG("SLINK_init: Could not allocate status structure\n");
- goto slink_initerr2;
- }
- cfg->status->seqstat = SLINK_COMPLETED;
- cfg->status->readstat = SLINK_COMPLETED;
-
-#ifdef SLINK_COLLECT_STATISTICS
- /* Allocate statistics structure and initialize members */
- if ((cfg->stats = calloc(1, sizeof(SLINK_stats))) == NULL) {
- DBG("SLINK_init: Could not allocate statistics structure\n");
- goto slink_initerr3;
- }
-#endif
-
- /* Allocate and initialize queues */
- if (SLINK_createqueues(qsize) == -1) {
- DBG("SLINK_init: Could not create queues\n");
- goto slink_initerr3;
- }
-
- /* Configure core registers */
- cfg->reg->clockscale = SLINK_calcscaler(SLINK_getsysfreq());
- cfg->reg->ctrl = parity ? SLINK_C_PAR : 0;
- cfg->reg->nullwrd = nullwrd;
- cfg->reg->msk = (SLINK_M_PERRE | SLINK_M_AERRE | SLINK_M_ROVE |
- SLINK_M_RNEE | SLINK_M_SAE | SLINK_M_SCE);
-
- /* Set-up INTERRUPT transfer handling */
- cfg->slink_irq_handler = interrupt_trans_handler;
-
- /* Save SEQUENCE callback */
- cfg->slink_seq_change = sequence_callback;
-
- /* Set-up IRQ handling */
- set_vector(SLINK_interrupt_handler,irq+0x10,2);
-
- return 0;
-
- slink_initerr3:
- free(cfg->status);
- slink_initerr2:
- free(cfg);
- slink_initerr1:
- return -1;
-}
-
-/* Function: SLINK_start
- * Description: Enables the core
- */
-void SLINK_start(void)
-{
- if (cfg != NULL)
- cfg->reg->ctrl |= SLINK_C_SLE;
-}
-
-/* Function: SLINK_stop
- * Description: Disables the core
- */
-void SLINK_stop(void)
-{
- if (cfg != NULL)
- cfg->reg->ctrl &= ~SLINK_C_SLE;
-}
-
-/*
- * Function: SLINK_read
- * Arguments: data: Payload of data word
- * channel: -
- * reply: Reply from IO card
- * Returns: 0 on success
- * -(SLINK_PARERR, SLINK_ROV) on error or -SLINK_QFULL if transmit queue
- * is full and software should try again.
- * Description: Reads one word and returns the response in *reply unless there
- * is an error. This function blocks until the READ operation is
- * completed or aborted.
- */
-int SLINK_read(int data, int channel, int *reply)
-{
- DBG("SLINK_read: called..");
-
- if (cfg->reg->sts & SLINK_S_TNF) {
- cfg->status->readstat = SLINK_ACTIVE;
- cfg->reg->td = SLINK_RW | channel << SLINK_CHAN_POS | data;
- } else {
- DBG("queue FULL\n");
- return -SLINK_QFULL; /* Transmit queue full */
- }
-
- /* Block until the operation has completed or has been aborted */
- rtems_semaphore_obtain(cfg->read_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
-
- if (cfg->status->readstat == SLINK_COMPLETED) {
- *reply = cfg->rword;
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->reads++;
-#endif
- DBG("returning 0\n");
- return 0;
- } else {
- DBG("returning error code\n");
- return -cfg->status->readstat;
- }
-}
-
-/*
- * Function: SLINK_write
- * Arguments: data: Payload of SLINK data word
- * channel: Channel value (bits 22 downto 16) of receive
- * register word
- * Returns: 0 if command was placed in transmit queue
- * -SLINK_QFULL if transmit queue was full (software should retry)
- * Description: See above.
- */
-int SLINK_write(int data, int channel)
-{
- if (cfg->reg->sts & SLINK_S_TNF) {
- cfg->reg->td = channel << SLINK_CHAN_POS | data;
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->writes++;
-#endif
- return 0;
- }
-
- return -SLINK_QFULL;
-}
-
-/*
- * Function: SLINK_sequence
- * Arguments: a: Array containing sequence commands
- * b: Array where SEQUENCE responses will be stored
- * n: Number of commands in a array
- * channel: Sequence Channel Number
- * reconly: Set to 1 if the SEQUENCE operation is receive only
- * Returns: 0 if SEQUENCE could be started (SUCCESS)
- * -1 if SEQUNCE was not started due to ongoing SEQUENCE
- */
-int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly)
-{
- /* Only start a new SEQUENCE of the former SEQUENCE has completed */
- if (cfg->status->seqstat == SLINK_ACTIVE ||
- cfg->status->seqstat == SLINK_PARERR)
- return -1;
-
- /* Tell core about arrays */
- cfg->reg->abase = (int)a;
- cfg->reg->bbase = (int)b;
-
- /* As far as software is concerned the sequence is now active */
- cfg->status->seqstat = SLINK_ACTIVE;
-
- /* Enable SEQUENCE operation with SCN = channel and SLEN = n-1 */
- if (reconly == 1) {
- cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) | SLINK_C_SRO |
- (channel << SLINK_C_SCN_POS) |
- SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
- } else {
- cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) |
- (channel << SLINK_C_SCN_POS) |
- SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
- }
-
-#ifdef SLINK_COLLECT_STATISTICS
- cfg->stats->sequences++;
-#endif
-
- return 0;
-}
-
-
-/* Function: SLINK_seqabort
- * Description: This function aborts an ongoing SEQUENCE. Software can tell
- * when the SEQUENCE is aborted by polling SLINK_seqstat().
- */
-void SLINK_seqabort(void)
-{
- cfg->reg->ctrl = cfg->reg->ctrl | SLINK_C_AS;
-}
-
-
-/*
- * Function: SLINK_seqstatus
- * Returns: The current or status of the SEQUENCE operation:
- * SLINK_COMPLETED, SLINK_ACTIVE, SLINK_PARERR, SLINK_AMBAERR,
- * SLINK_ABORTED (these are defined in bsp/grslink.h)
- * Description: Meaning of returned values:
- * SLINK_ABORTED: Aborted before all operations completed.
- * SLINK_ACTIVE: The core is busy processing the SEQUENCE
- * SLINK_AMBAERR: The last SEQUENCE was aborted by an AMBA ERROR
- * SLINK_COMPLETED: All words were transferred in the last SEQUENCE
- * SLINK_PARERR: Parity error detected. Software may want to abort
- *
- * If the SEQUENCE was aborted SLINK_seqwrds() can be used to
- * determine the number of completed operations.
- */
-int SLINK_seqstatus(void)
-{
- return cfg->status->seqstat;
-}
-
-/*
- * Function: SLINK_seqwrds
- * Returns: -1 for ongoing sequence
- * 0 if all words were transferred in the last sequence
- * number of words if the last SEQUENCE did not complete
- * (SLINK_AMBAERR or SLINK_ABORTED is reported ny SLINK_seqstatus())
- */
-int SLINK_seqwrds(void)
-{
- switch (cfg->status->seqstat) {
- case SLINK_COMPLETED: return 0;
- case SLINK_ACTIVE | SLINK_PARERR: return -1;
- default: return cfg->status->scnt;
- }
-}
-
-/*
- * Function: SLINK_hwstatus
- * Returns: The SLINK core's status register. The register values can be
- * interpreted with the help of macros defined in bsp/grslink.h.
- */
-int SLINK_hwstatus(void)
-{
- return cfg->reg->sts;
-}
-
-/*
- * Function: SLINK_queuestatus
- * Arguments: iocard: Queue which to check status for
- * Returns: Number of elements in queue or -1 on non-existent queue
- * Description: SLINK_queuestatus(queue) returns the number of elements in
- * queue 'iocard'
- */
-int SLINK_queuestatus(int iocard)
-{
- unsigned int first, last;
- SLINK_queue *ioq;
-
- if (iocard >= SLINK_NUMQUEUES)
- return -1;
-
- ioq = cfg->queues + iocard;
-
- if (ioq->full)
- return ioq->size;
- if (ioq->first == ioq->last)
- return 0;
-
- first = ((unsigned int)ioq->first)/sizeof(unsigned int);
- last = ((unsigned int)ioq->last)/sizeof(unsigned int);
-
- return first < last ? last - first : ioq->size - first + last;
-}
-
-/*
- * Function: SLINK_dequeue
- * Arguments: iocard: IO card number
- * elem: First element in IO card queue
- * Returns: 0 on success or -1 on empty or non-existent queue
- * Description:
- */
-int SLINK_dequeue(int iocard, int *elem)
-{
- if (iocard >= SLINK_NUMQUEUES)
- return -1;
-
- SLINK_queue *ioq = cfg->queues + iocard;
-
- if (ioq->last != ioq->first || ioq->full) {
- *elem = *ioq->first;
- ioq->first = (ioq->first >= ioq->max) ? ioq->buf : ioq->first+1;
- ioq->full = 0;
- return 0;
- }
- return -1;
-}
-
-/*
- * Function: SLINK_statistics
- * Returns: If the core has statistics colletion enabled this function returns
- * a pointer to a struct containing statistics information, otherwise NULL.
- */
-SLINK_stats *SLINK_statistics(void)
-{
-#ifdef SLINK_COLLECT_STATISTICS
- return cfg->stats;
-#else
- return NULL;
-#endif
-}