Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:06

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  This file contains the GRASCS RTEMS driver
0004  *
0005  *  COPYRIGHT (c) 2008.
0006  *  Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #include <stdlib.h>
0031 #include <bsp.h>
0032 #include <grlib/ambapp.h>
0033 #include <grlib/grascs.h>
0034 #include <grlib/grlib.h>
0035 
0036 #include <grlib/grlib_impl.h>
0037 
0038 #ifndef GAISLER_ASCS
0039 #define GAISLER_ASCS 0x043
0040 #endif
0041 
0042 #ifdef DEBUG
0043 #define DBG(x...) printk(x)
0044 #else
0045 #define DBG(x...)
0046 #endif
0047 
0048 typedef struct {
0049   volatile unsigned int cmd;
0050   volatile unsigned int clk;
0051   volatile unsigned int sts;
0052   volatile unsigned int tcd;
0053   volatile unsigned int tmd;
0054 } GRASCS_regs;
0055 
0056 typedef struct {
0057   unsigned char tmconf;
0058   unsigned char usconf;
0059   unsigned char nslaves;
0060   unsigned char dbits;
0061   int clkfreq;
0062 } GRASCS_caps;
0063 
0064 typedef struct {
0065   GRASCS_regs *regs; /* Pointer to core registers */
0066   GRASCS_caps *caps; /* Pointer to capability struct */
0067   rtems_id tcsem1, tcsem2;
0068   rtems_id tmsem1, tmsem2;
0069   volatile char running;
0070   int tcptr;
0071   int tmptr;
0072   int tcwords;
0073   int tmwords;
0074 } GRASCS_cfg;
0075 
0076 static GRASCS_cfg *cfg = NULL;
0077 
0078 /*------------------------------------*/
0079 /* Start of internal helper functions */ 
0080 /*------------------------------------*/
0081 
0082 /* Function: ASCS_getaddr
0083    Arguments: base: Core's register base address
0084               irq: Core's irq
0085    Return values: 0 if successful, -1 if core is not found
0086    Description: Assigns core's register base address and
0087      irq to arguments. Uses AMBA plug and play to find the
0088      core.
0089 */
0090 static int ASCS_get_addr(int *base, int *irq) {
0091 
0092   struct ambapp_apb_info core;
0093   
0094   if(ambapp_find_apbslv(ambapp_plb(), VENDOR_GAISLER, GAISLER_ASCS, &core) == 1) {
0095     *base = core.start;
0096     *irq = core.common.irq;
0097     DBG("ASCS_get_addr: Registerd ASCS core at 0x%x with irq %i\n",core.start, core.irq);
0098     return 0;
0099   }
0100   DBG("ASCS_get_addr: Failed to detect core\n");
0101   return -1;  
0102 }
0103 
0104 /* Function: ASCS_calc_clkreg
0105    Arguments: sysfreq: System clock frequency in kHz
0106               etrfreq: ETR frequency in Hz
0107    Return values: Value of core's CLK-register
0108    Description: Calculates value of core's CLK-register. See
0109      GRASCS IP core documentation for details.
0110 */
0111 static int ASCS_calc_clkreg(int sysfreq, int etrfreq) {
0112 
0113   if(cfg->caps->usconf)
0114     return 1000000/etrfreq;
0115   else
0116     return sysfreq*1000/etrfreq;
0117 }
0118 
0119 /* Function: ASCS_get_sysfreq
0120    Arguments: - 
0121    Return values: System clock frequency in kHz, -1 if failed
0122    Description: Uses AMBA plug and play to lookup system frequency
0123 */
0124 static int ASCS_get_sysfreq(void) {
0125 
0126   struct ambapp_apb_info gpt;
0127   struct gptimer_regs *tregs;
0128   int tmp;
0129 
0130   if(ambapp_find_apbslv(ambapp_plb(), VENDOR_GAISLER, GAISLER_GPTIMER, &gpt) == 1) {
0131     tregs = (struct gptimer_regs *) gpt.start;
0132     tmp = (tregs->scaler_reload + 1)*1000;
0133     DBG("ASCS_get_sysfreq: Detected system frequency %i kHz\n",tmp);
0134     if((tmp < GRASCS_MIN_SFREQ) || (tmp > GRASCS_MAX_SFREQ)) {
0135       DBG("ASCS_get_sysfreq: System frequency is invalid for ASCS core\n");
0136       return -1;
0137     }
0138     else
0139       return (tregs->scaler_reload + 1)*1000;
0140   }
0141   DBG("ASCS_get_sysfreq: Failed to detect system frequency\n");
0142   return -1;
0143 }
0144 
0145 /* Function: ASCS_irqhandler
0146    Arguments: v: not used
0147    Return values: -
0148    Description: Determines the source of the interrupt, clears the
0149                 appropriate bits in the core's STS register and releases
0150         the associated semaphore
0151 */
0152 static rtems_isr ASCS_irqhandler(void *v) {
0153 
0154   if(cfg->regs->sts & GRASCS_STS_TCDONE) {
0155     /* Clear TC done bit */
0156     cfg->regs->sts |= GRASCS_STS_TCDONE;    
0157 
0158     if(--cfg->tcwords == 0)
0159       /* No more TCs to perform right now */
0160       rtems_semaphore_release(cfg->tcsem2);
0161     else {
0162       /* Block not sent yet, start next TC */
0163       if(cfg->caps->dbits == 8) {
0164     cfg->tcptr++;
0165     cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
0166       }
0167       else if(cfg->caps->dbits == 16) {
0168     cfg->tcptr += 2;
0169     cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
0170       }
0171       else {
0172     cfg->tcptr += 4;
0173     cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
0174       }
0175     }
0176   }
0177 
0178   if(cfg->regs->sts & GRASCS_STS_TMDONE) {
0179     /* Clear TM done bit */
0180     cfg->regs->sts |= GRASCS_STS_TMDONE;
0181 
0182     /* Store received data */
0183     if(cfg->caps->dbits == 8) {
0184       *((unsigned char*)cfg->tmptr) = (unsigned char)(cfg->regs->tmd & 0xFF);
0185       cfg->tmptr++;
0186     }
0187     else if(cfg->caps->dbits == 16) {
0188       *((unsigned short int*)cfg->tmptr) = (unsigned short int)(cfg->regs->tmd & 0xFFFF);
0189       cfg->tmptr += 2;
0190     }
0191     else {
0192       *((unsigned int*)cfg->tmptr) = cfg->regs->tmd;
0193       cfg->tmptr += 4;
0194     }
0195     
0196     if(--cfg->tmwords == 0)
0197       /* No more TMs to perform right now */
0198       rtems_semaphore_release(cfg->tmsem2);
0199     else
0200       /* Block not received yet, start next TM */
0201       cfg->regs->cmd |= GRASCS_CMD_SENDTM;      
0202   }
0203 }
0204 
0205 /*---------------------------*/
0206 /* Start of driver interface */
0207 /*---------------------------*/
0208 
0209 /* Function: ASCS_init
0210    Arguments: -
0211    Return values: 0 if successful, -1 if unsuccessful
0212    Description: Initializes the ASCS core
0213 */
0214 int ASCS_init(void) {
0215 
0216   int base, irq, tmp;
0217 
0218   DBG("ASCS_init: Starting initialization of ASCS core\n");
0219   
0220   /* Allocate memory for config, status and capability struct */
0221   if((cfg = grlib_malloc(sizeof(*cfg))) == NULL) {
0222     DBG("ASCS_init: Could not allocate memory for cfg struc\n");
0223     return -1;
0224   }
0225   
0226   if((cfg->caps = grlib_calloc(1,sizeof(*cfg->caps))) == NULL) {
0227     DBG("ASCS_init: Could not allocate memory for caps struc\n");
0228     goto init_error1;
0229   }
0230     
0231   /* Create semaphores for blocking ASCS_TC/TM functions */
0232   if(rtems_semaphore_create(rtems_build_name('A','S','C','0'),1,
0233                 (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
0234                  RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
0235                  RTEMS_NO_PRIORITY_CEILING), 0,
0236                 &cfg->tcsem1) != RTEMS_SUCCESSFUL) {
0237     DBG("ASCS_init: Failed to create semaphore ASC0\n");
0238     goto init_error2;
0239   }
0240   if(rtems_semaphore_create(rtems_build_name('A','S','C','1'),1,
0241                 (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
0242                  RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
0243                  RTEMS_NO_PRIORITY_CEILING), 0,
0244                 &cfg->tmsem1) != RTEMS_SUCCESSFUL) {
0245     DBG("ASCS_init: Failed to create semaphore ASC1\n");
0246     goto init_error2;
0247   }
0248   /* Create semaphores for waiting on ASCS_TC/TM interrupt */
0249   if(rtems_semaphore_create(rtems_build_name('A','S','C','2'),0,
0250                 (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
0251                  RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
0252                  RTEMS_NO_PRIORITY_CEILING), 0,
0253                 &cfg->tcsem2) != RTEMS_SUCCESSFUL) {
0254     DBG("ASCS_init: Failed to create semaphore ASC2\n");
0255     goto init_error2;
0256   }
0257   if(rtems_semaphore_create(rtems_build_name('A','S','C','3'),0,
0258                 (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
0259                  RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
0260                  RTEMS_NO_PRIORITY_CEILING), 0,
0261                 &cfg->tmsem2) != RTEMS_SUCCESSFUL) {
0262     DBG("ASCS_init: Failed to create semaphore ASC3\n");
0263     goto init_error2;
0264   }
0265 
0266   /* Set pointer to core registers */
0267   if(ASCS_get_addr(&base, &irq) == -1)
0268     goto init_error2;
0269 
0270   cfg->regs = (GRASCS_regs*)base;
0271   
0272   /* Read core capabilities */
0273   tmp = cfg->regs->sts;
0274   cfg->caps->dbits = ((tmp >> GRASCS_STS_DBITS_BITS) & 0x1F) + 1;
0275   cfg->caps->nslaves = ((tmp >> GRASCS_STS_NSLAVES_BITS) & 0xF) + 1;
0276   cfg->caps->tmconf = (tmp >> GRASCS_STS_TMCONF_BITS) & 0x1;
0277   cfg->caps->usconf = (tmp >> GRASCS_STS_USCONF_BITS) & 0x1;
0278 
0279   /* Reset and configure core */
0280   cfg->running = 0;
0281   cfg->regs->cmd |= GRASCS_CMD_RESET;
0282   if((tmp = ASCS_get_sysfreq()) == -1)
0283     goto init_error2;
0284   cfg->caps->clkfreq = tmp;
0285   while(ASCS_iface_status())
0286     ;  
0287   cfg->regs->clk = ASCS_calc_clkreg(tmp, GRASCS_DEFAULT_ETRFREQ);
0288   cfg->regs->cmd = GRASCS_CMD_US1C;
0289   cfg->regs->cmd |= (tmp/1000 << GRASCS_CMD_US1_BITS) | GRASCS_CMD_US1C |
0290     GRASCS_CMD_TCDONE | GRASCS_CMD_TMDONE;
0291 
0292   /* Register interrupt routine */
0293   rtems_interrupt_handler_install(irq, "grascs",
0294           RTEMS_INTERRUPT_SHARED,
0295           ASCS_irqhandler, NULL);
0296   
0297   return 0;
0298 
0299  init_error2:
0300   free(cfg->caps);
0301  init_error1:
0302   free(cfg);
0303   return -1;
0304 }
0305 
0306 /* Function: ASCS_input_select
0307    Arguments: slave: The number of the slave that is active,
0308               numbered from 0-15
0309    Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if slave value
0310                   is negative or too big, -GRASCS_ERROR_TRANSACTIVE if
0311           a TM is active.
0312    Description: Sets the slave_sel bits in the core's CMD register.
0313                 they are used to choose which slave the core listens
0314         to when performing a TM. The bits can't be set
0315         during a TM, and the function will in such a case fail.
0316 */
0317 int ASCS_input_select(int slave) {
0318 
0319   if((slave < 0) || (slave > cfg->caps->nslaves)) {
0320     /* Slave number is negative or too big */
0321     DBG("ASCS_input_select: Wrong slave number\n");
0322     return -GRASCS_ERROR_CAPFAULT;
0323   }
0324     
0325   if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
0326      RTEMS_SUCCESSFUL) {
0327     /* Can't change active slave during a TM */
0328     DBG("ASCS_input_select: Transaction active\n");
0329     return -GRASCS_ERROR_TRANSACTIVE;
0330   }
0331   
0332   cfg->regs->cmd = ((cfg->regs->cmd & ~GRASCS_CMD_SLAVESEL) |
0333             (slave << GRASCS_CMD_SLAVESEL_BITS));
0334 
0335   rtems_semaphore_release(cfg->tmsem1);
0336   return 0;
0337 }
0338 
0339 /* Function: ASCS_etr_select
0340    Arguments: src: The source of the ETR signal, valid values are
0341                    0-GRASCS_MAX_TMS (0 = internal source, 1-GRASCS_MAX_TMS =
0342            external time markers 1-GRASCS_MAX_TMS).
0343           freq: ETR frequency in Hz. Valid values are
0344                 GRASCS_MIN_ETRFREQ-GRASCS_MAX_ETRFREQ
0345    Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if src or freq values
0346                   are invalid, -GRASCS_ERROR_STARTSTOP if synchronization interface
0347           isn't stopped.
0348    Description: Changes the source for the ETR signal. The frequency of source signal
0349                 is assumed to be the same as the frequency of the freq input
0350 */
0351 int ASCS_etr_select(int etr, int freq) {
0352   
0353   if((etr < 0) || (etr > GRASCS_MAX_TMS) || ((cfg->caps->tmconf == 0) && (etr > 0)) ||
0354      (freq < GRASCS_MIN_ETRFREQ) || (freq > GRASCS_MAX_ETRFREQ)) {
0355     /* ETR source value or frequency is invalid */
0356     DBG("ASCS_etr_select: Wrong etr src number or wrong frequency\n");
0357     return -GRASCS_ERROR_CAPFAULT;
0358   }
0359   
0360   if(cfg->regs->sts & GRASCS_STS_ERUNNING) {
0361     /* Synchronization interface is running */
0362     DBG("ASCS_etr_select: Synch interface is running\n");
0363     return -GRASCS_ERROR_STARTSTOP;
0364   }
0365   
0366   cfg->regs->clk = ASCS_calc_clkreg(cfg->caps->clkfreq,freq);
0367   cfg->regs->cmd = ((cfg->regs->cmd & ~GRASCS_CMD_ETRCTRL) |
0368             (etr << GRASCS_CMD_ETRCTRL_BITS));
0369 
0370   return 0;
0371 }
0372 
0373 /* Function: ASCS_start
0374    Arguments: -
0375    Return values: -
0376    Description: Enables the serial interface. 
0377 */
0378 void ASCS_start(void) {
0379   
0380   /* Set register and internal status to running */
0381   cfg->regs->cmd |= GRASCS_CMD_STARTSTOP;
0382   cfg->running = 1;
0383 }
0384 
0385 /* Function: ASCS_stop
0386    Arguments: -
0387    Return values: -
0388    Description: Disables the serial interface. This function will
0389                 block until possible calls to TC_send(_block) and
0390         TM_recv(_block) has returned in order to be sure
0391         that started transactions will be performed.
0392 */
0393 void ASCS_stop(void) {
0394 
0395   /* Set internal status to stopped */
0396   cfg->running = 0;
0397 
0398   /* Obtain semaphores to avoid possible situation where a
0399      TC_send(_block) or TM_recv(_block) is aborted and driver is
0400      waiting forever for an interrupt */
0401   rtems_semaphore_obtain(cfg->tcsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0402   rtems_semaphore_obtain(cfg->tmsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0403 
0404   /* Change actual register value */
0405   cfg->regs->cmd &= ~GRASCS_CMD_STARTSTOP;
0406 
0407   /* Release the semaphores */
0408   rtems_semaphore_release(cfg->tcsem1);
0409   rtems_semaphore_release(cfg->tmsem1);
0410 }
0411 
0412 /* Function: ASCS_iface_status
0413    Arguments: - 
0414    Return values: 0 if both serial interface and synch interface is stopped,
0415                   1 if serial interface is running buth synch interface is
0416           stopped, 2 if serial interface is stopped but synch interface
0417           is running, 3 if both serial and synch interface is running
0418    Description: Reads the core's STS register and reports the status of the
0419                 serial and synch interfaces
0420 */
0421 int ASCS_iface_status(void) {
0422 
0423   return ((cfg->regs->sts & 0x3) & (0x2 | cfg->running));
0424 }
0425 
0426 /* Function: ASCS_TC_send
0427    Arguments: word: Pointer to a word that should be sent
0428    Return values: 0 on success
0429                   -GRASCS_ERROR_STARTSTOP if serial interface is stopped,
0430           -GRASCS_ERROR_TRANSACTIVE if another TC is in progress.
0431    Description: Start a TC and sends the data that word points to.
0432 */
0433 int ASCS_TC_send(int *word) {
0434 
0435   int retval;
0436 
0437   if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
0438      RTEMS_SUCCESSFUL) {
0439     /* Can't start a TC_send if another TC_send of TC_send_block is
0440        in progress */
0441     DBG("ASCS_TC_send: Could not obtain semaphore, transcation probably in progress\n");
0442     return -GRASCS_ERROR_TRANSACTIVE;
0443   }
0444     
0445   if(!cfg->running) {
0446     /* Can't start a TC if serial interface isn't started */
0447     DBG("ASCS_TC_send: Serial interface is not started\n");
0448     retval = -GRASCS_ERROR_STARTSTOP;
0449   }
0450   else {
0451     /* Start the transfer */
0452     cfg->tcwords = 1;
0453     if(cfg->caps->dbits == 8)
0454       cfg->regs->tcd = *((unsigned char*)word);
0455     else if(cfg->caps->dbits == 16)
0456       cfg->regs->tcd = *((unsigned short int*)((int)word & ~1));
0457     else
0458       cfg->regs->tcd = *((unsigned int*)((int)word & ~3));
0459     
0460     /* Wait until transfer is complete */
0461     rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0462     retval = 0;
0463   }
0464 
0465   rtems_semaphore_release(cfg->tcsem1);
0466   
0467   return retval;
0468 }
0469 
0470 /* Function: ASCS_TC_send_block
0471    Arguments: block: Pointer to the start of a datablock that
0472                      should be sent.
0473           ntrans: Number of transfers needed to transfer
0474                   the block.
0475    Return values: 0 if successfull, -GRASCS_ERROR_STARTSTOP if TC
0476                   couldn't be started because serial interface is
0477                   stopped, -GRASCS_ERROR_TRANSACTIVE if TC couldn't
0478           be started because another TC isn't done yet.
0479    Description: Starts ntrans TCs and sends the data that starts at the
0480                 address that block points to. The size of each
0481         transaction will vary depending on whether the core is
0482         configured for 8, 16, or 32 bits data transfers.
0483 */
0484 int ASCS_TC_send_block(int *block, int ntrans) {
0485 
0486   int retval;
0487 
0488   if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
0489      RTEMS_SUCCESSFUL) {
0490     /* Can't start a TC_send_block if another TC_send of TC_send_block is
0491        in progress */
0492     DBG("ASCS_TC_send_block: Could not obtain semaphore, transcation probably in progress\n");
0493     return -GRASCS_ERROR_TRANSACTIVE;
0494   }
0495 
0496   if(!cfg->running) {
0497     /* Can't start a TC if serial interface isn't started */
0498     DBG("ASCS_TC_send_block: Serial interface is not started\n");
0499     retval = -GRASCS_ERROR_STARTSTOP;
0500   }
0501   else {
0502     /* Start the first transfer */
0503     cfg->tcwords = ntrans;
0504     if(cfg->caps->dbits == 8) {
0505       cfg->tcptr = (int)block;
0506       cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
0507     }
0508     else if(cfg->caps->dbits == 16) {
0509       cfg->tcptr = (int)block & ~1;
0510       cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
0511     }
0512     else {
0513       cfg->tcptr = (int)block & ~3;
0514       cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
0515     }
0516         
0517     /* Wait until all transfers are complete */
0518     rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0519     retval = 0;
0520   }
0521   
0522   rtems_semaphore_release(cfg->tcsem1);
0523 
0524   return retval;
0525 }
0526 
0527 /* Function: ASCS_TC_sync_start
0528    Arguments: -
0529    Return values: -
0530    Description: Starts synchronization interface. Might
0531      be delayed if a TM is in progress. SW can poll
0532      ASCS_iface_status() to find out when synch interface is
0533      started. First ETR pulse can be delay up to one ETR
0534      period depending on the source of the ETR and
0535      activity on the TM line.
0536 */
0537 void ASCS_TC_sync_start(void) {
0538   
0539   cfg->regs->cmd |= GRASCS_CMD_ESTARTSTOP;
0540 }
0541 
0542 /* Function: ASCS_TC_sync_stop
0543    Arguments: -
0544    Return values: -
0545    Description: Stops the synchronization interface. Might
0546      be delayed for 1 us if a ETR pulse is being generated. SW
0547      can determine when synch interface has stopped by polling
0548      ASCS_iface_status().
0549 */
0550 void ASCS_TC_sync_stop(void) {
0551   
0552   cfg->regs->cmd &= ~GRASCS_CMD_ESTARTSTOP;
0553 }
0554 
0555 /* Function: ASCS_TM_recv
0556    Arguments: word: Pointer to where the received word should be
0557                     placed
0558    Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
0559                   interface isn't started, -GRASCS_ERROR_TRANSACTIVE
0560           if another TM is in progress
0561    Description: Starts a TM and stores the incoming data in word.
0562 */
0563 int ASCS_TM_recv(int *word) {
0564 
0565   int retval;
0566 
0567   if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
0568      RTEMS_SUCCESSFUL) {
0569     /* Can't start a TM_recv if another TM_recv of TM_recv_block is
0570        in progress */
0571     DBG("ASCS_TM_recv: Could not obtain semaphore, transaction probably in progress\n");
0572     return -GRASCS_ERROR_TRANSACTIVE;
0573   }
0574 
0575   if(!cfg->running) {
0576     /* Can't start a TM if serial interface isn't started */
0577     DBG("ASCS_TM_recv: Serial interface is not started\n");
0578     retval = -GRASCS_ERROR_STARTSTOP;
0579   }
0580   else {
0581     /* Start transfer */
0582     cfg->tmwords = 1;
0583     cfg->tmptr = (int)word;
0584     cfg->regs->cmd |= GRASCS_CMD_SENDTM;
0585     
0586     /* Wait until transfer finishes */
0587     rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0588     retval = 0;
0589   }
0590 
0591   rtems_semaphore_release(cfg->tmsem1);
0592 
0593   return retval;
0594 }
0595 
0596 /* Function: ASCS_TM_recv_block
0597    Arguments: block: Pointer to where the received datablock
0598                      should be stored.
0599           ntrans: Number of transfers needed to transfer
0600                   the block.
0601    Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
0602                   interface isn't started, -GRASCS_ERROR_TRANSACTIVE if
0603           a performed TM hasn't been processed yet
0604    Description: Starts ntrans TMs and stores the data at the address
0605                 that block points to. The size of each transaction
0606         will vary depending on whether the core is
0607         configured for 8, 16, or 32 bits data transfers.
0608 */
0609 int ASCS_TM_recv_block(int *block, int ntrans) {
0610 
0611   int retval;
0612 
0613   if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
0614      RTEMS_SUCCESSFUL) {
0615     /* Can't start a TM_recv_block if another TM_recv of TM_recv_block is
0616        in progress */
0617     DBG("ASCS_TM_recv_block: Could not obtain semaphore, transaction probably in progress\n");
0618     return -GRASCS_ERROR_TRANSACTIVE;
0619   }
0620 
0621   if(!cfg->running) {
0622     /* Can't start a TM if serial interface isn't started */
0623     DBG("ASCS_TM_recv_block: Serial interface is not started\n");
0624     retval = -GRASCS_ERROR_STARTSTOP;
0625   }
0626   else {
0627     /* Start transfer */
0628     cfg->tmwords = ntrans;
0629     cfg->tmptr = (int)block;
0630     cfg->regs->cmd |= GRASCS_CMD_SENDTM;
0631     
0632     /* Wait until transfer finishes */
0633     rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0634     retval = 0;
0635   }
0636 
0637   rtems_semaphore_release(cfg->tmsem1);
0638 
0639   return retval;
0640 }