diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/slink/grslink.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/slink/grslink.c | 661 |
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 -} |