source: rtems/bsps/shared/grlib/ascs/grascs.c @ 7eb606d3

Last change on this file since 7eb606d3 was 7eb606d3, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 22, 2018 at 5:31:04 PM

grlib: Move source files

Update #3678.

  • Property mode set to 100644
File size: 18.9 KB
Line 
1/*  This file contains the GRASCS RTEMS driver
2 *
3 *  COPYRIGHT (c) 2008.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.org/license/LICENSE.
9 */
10
11#include <stdlib.h>
12#include <bsp.h>
13#include <grlib/ambapp.h>
14#include <grlib/grascs.h>
15#include <grlib/grlib.h>
16
17#include <grlib/grlib_impl.h>
18
19#ifndef GAISLER_ASCS
20#define GAISLER_ASCS 0x043
21#endif
22
23#ifdef DEBUG
24#define DBG(x...) printk(x)
25#else
26#define DBG(x...)
27#endif
28
29typedef struct {
30  volatile unsigned int cmd;
31  volatile unsigned int clk;
32  volatile unsigned int sts;
33  volatile unsigned int tcd;
34  volatile unsigned int tmd;
35} GRASCS_regs;
36
37typedef struct {
38  unsigned char tmconf;
39  unsigned char usconf;
40  unsigned char nslaves;
41  unsigned char dbits;
42  int clkfreq;
43} GRASCS_caps;
44
45typedef struct {
46  GRASCS_regs *regs; /* Pointer to core registers */
47  GRASCS_caps *caps; /* Pointer to capability struct */
48  rtems_id tcsem1, tcsem2;
49  rtems_id tmsem1, tmsem2;
50  volatile char running;
51  int tcptr;
52  int tmptr;
53  int tcwords;
54  int tmwords;
55} GRASCS_cfg;
56
57static GRASCS_cfg *cfg = NULL;
58
59/*------------------------------------*/
60/* Start of internal helper functions */ 
61/*------------------------------------*/
62
63/* Function: ASCS_getaddr
64   Arguments: base: Core's register base address
65              irq: Core's irq
66   Return values: 0 if successful, -1 if core is not found
67   Description: Assigns core's register base address and
68     irq to arguments. Uses AMBA plug and play to find the
69     core.
70*/
71static int ASCS_get_addr(int *base, int *irq) {
72
73  struct ambapp_apb_info core;
74 
75  if(ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_ASCS, &core) == 1) {
76    *base = core.start;
77    *irq = core.irq;
78    DBG("ASCS_get_addr: Registerd ASCS core at 0x%x with irq %i\n",core.start, core.irq);
79    return 0;
80  }
81  DBG("ASCS_get_addr: Failed to detect core\n");
82  return -1; 
83}
84
85/* Function: ASCS_calc_clkreg
86   Arguments: sysfreq: System clock frequency in kHz
87              etrfreq: ETR frequency in Hz
88   Return values: Value of core's CLK-register
89   Description: Calculates value of core's CLK-register. See
90     GRASCS IP core documentation for details.
91*/
92static int ASCS_calc_clkreg(int sysfreq, int etrfreq) {
93
94  if(cfg->caps->usconf)
95    return 1000000/etrfreq;
96  else
97    return sysfreq*1000/etrfreq;
98}
99
100/* Function: ASCS_get_sysfreq
101   Arguments: -
102   Return values: System clock frequency in kHz, -1 if failed
103   Description: Uses AMBA plug and play to lookup system frequency
104*/
105static int ASCS_get_sysfreq(void) {
106
107  struct ambapp_apb_info gpt;
108  struct gptimer_regs *tregs;
109  int tmp;
110
111  if(ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, &gpt) == 1) {
112    tregs = (struct gptimer_regs *) gpt.start;
113    tmp = (tregs->scaler_reload + 1)*1000;
114    DBG("ASCS_get_sysfreq: Detected system frequency %i kHz\n",tmp);
115    if((tmp < GRASCS_MIN_SFREQ) || (tmp > GRASCS_MAX_SFREQ)) {
116      DBG("ASCS_get_sysfreq: System frequency is invalid for ASCS core\n");
117      return -1;
118    }
119    else
120      return (tregs->scaler_reload + 1)*1000;
121  }
122  DBG("ASCS_get_sysfreq: Failed to detect system frequency\n");
123  return -1;
124}
125
126/* Function: ASCS_irqhandler
127   Arguments: v: not used
128   Return values: -
129   Description: Determines the source of the interrupt, clears the
130                appropriate bits in the core's STS register and releases
131                the associated semaphore
132*/
133static rtems_isr ASCS_irqhandler(rtems_vector_number v) {
134
135  if(cfg->regs->sts & GRASCS_STS_TCDONE) {
136    /* Clear TC done bit */
137    cfg->regs->sts |= GRASCS_STS_TCDONE;   
138
139    if(--cfg->tcwords == 0)
140      /* No more TCs to perform right now */
141      rtems_semaphore_release(cfg->tcsem2);
142    else {
143      /* Block not sent yet, start next TC */
144      if(cfg->caps->dbits == 8) {
145        cfg->tcptr++;
146        cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
147      }
148      else if(cfg->caps->dbits == 16) {
149        cfg->tcptr += 2;
150        cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
151      }
152      else {
153        cfg->tcptr += 4;
154        cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
155      }
156    }
157  }
158
159  if(cfg->regs->sts & GRASCS_STS_TMDONE) {
160    /* Clear TM done bit */
161    cfg->regs->sts |= GRASCS_STS_TMDONE;
162
163    /* Store received data */
164    if(cfg->caps->dbits == 8) {
165      *((unsigned char*)cfg->tmptr) = (unsigned char)(cfg->regs->tmd & 0xFF);
166      cfg->tmptr++;
167    }
168    else if(cfg->caps->dbits == 16) {
169      *((unsigned short int*)cfg->tmptr) = (unsigned short int)(cfg->regs->tmd & 0xFFFF);
170      cfg->tmptr += 2;
171    }
172    else {
173      *((unsigned int*)cfg->tmptr) = cfg->regs->tmd;
174      cfg->tmptr += 4;
175    }
176   
177    if(--cfg->tmwords == 0)
178      /* No more TMs to perform right now */
179      rtems_semaphore_release(cfg->tmsem2);
180    else
181      /* Block not received yet, start next TM */
182      cfg->regs->cmd |= GRASCS_CMD_SENDTM;     
183  }
184}
185
186/*---------------------------*/
187/* Start of driver interface */
188/*---------------------------*/
189
190/* Function: ASCS_init
191   Arguments: -
192   Return values: 0 if successful, -1 if unsuccessful
193   Description: Initializes the ASCS core
194*/
195int ASCS_init(void) {
196
197  int base, irq, tmp;
198
199  DBG("ASCS_init: Starting initialization of ASCS core\n");
200 
201  /* Allocate memory for config, status and capability struct */
202  if((cfg = grlib_malloc(sizeof(*cfg))) == NULL) {
203    DBG("ASCS_init: Could not allocate memory for cfg struc\n");
204    return -1;
205  }
206 
207  if((cfg->caps = grlib_calloc(1,sizeof(*cfg->caps))) == NULL) {
208    DBG("ASCS_init: Could not allocate memory for caps struc\n");
209    goto init_error1;
210  }
211   
212  /* Create semaphores for blocking ASCS_TC/TM functions */
213  if(rtems_semaphore_create(rtems_build_name('A','S','C','0'),1,
214                            (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
215                             RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
216                             RTEMS_NO_PRIORITY_CEILING), 0,
217                            &cfg->tcsem1) != RTEMS_SUCCESSFUL) {
218    DBG("ASCS_init: Failed to create semaphore ASC0\n");
219    goto init_error2;
220  }
221  if(rtems_semaphore_create(rtems_build_name('A','S','C','1'),1,
222                            (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
223                             RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
224                             RTEMS_NO_PRIORITY_CEILING), 0,
225                            &cfg->tmsem1) != RTEMS_SUCCESSFUL) {
226    DBG("ASCS_init: Failed to create semaphore ASC1\n");
227    goto init_error2;
228  }
229  /* Create semaphores for waiting on ASCS_TC/TM interrupt */
230  if(rtems_semaphore_create(rtems_build_name('A','S','C','2'),0,
231                            (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
232                             RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
233                             RTEMS_NO_PRIORITY_CEILING), 0,
234                            &cfg->tcsem2) != RTEMS_SUCCESSFUL) {
235    DBG("ASCS_init: Failed to create semaphore ASC2\n");
236    goto init_error2;
237  }
238  if(rtems_semaphore_create(rtems_build_name('A','S','C','3'),0,
239                            (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
240                             RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
241                             RTEMS_NO_PRIORITY_CEILING), 0,
242                            &cfg->tmsem2) != RTEMS_SUCCESSFUL) {
243    DBG("ASCS_init: Failed to create semaphore ASC3\n");
244    goto init_error2;
245  }
246
247  /* Set pointer to core registers */
248  if(ASCS_get_addr(&base, &irq) == -1)
249    goto init_error2;
250
251  cfg->regs = (GRASCS_regs*)base;
252 
253  /* Read core capabilities */
254  tmp = cfg->regs->sts;
255  cfg->caps->dbits = ((tmp >> GRASCS_STS_DBITS_BITS) & 0x1F) + 1;
256  cfg->caps->nslaves = ((tmp >> GRASCS_STS_NSLAVES_BITS) & 0xF) + 1;
257  cfg->caps->tmconf = (tmp >> GRASCS_STS_TMCONF_BITS) & 0x1;
258  cfg->caps->usconf = (tmp >> GRASCS_STS_USCONF_BITS) & 0x1;
259
260  /* Reset and configure core */
261  cfg->running = 0;
262  cfg->regs->cmd |= GRASCS_CMD_RESET;
263  if((tmp = ASCS_get_sysfreq()) == -1)
264    goto init_error2;
265  cfg->caps->clkfreq = tmp;
266  while(ASCS_iface_status())
267    ; 
268  cfg->regs->clk = ASCS_calc_clkreg(tmp, GRASCS_DEFAULT_ETRFREQ);
269  cfg->regs->cmd = GRASCS_CMD_US1C;
270  cfg->regs->cmd |= (tmp/1000 << GRASCS_CMD_US1_BITS) | GRASCS_CMD_US1C |
271    GRASCS_CMD_TCDONE | GRASCS_CMD_TMDONE;
272
273  /* Register interrupt routine */
274  set_vector(ASCS_irqhandler,irq+0x10,2);
275 
276  return 0;
277
278 init_error2:
279  free(cfg->caps);
280 init_error1:
281  free(cfg);
282  return -1;
283}
284
285/* Function: ASCS_input_select
286   Arguments: slave: The number of the slave that is active,
287              numbered from 0-15
288   Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if slave value
289                  is negative or too big, -GRASCS_ERROR_TRANSACTIVE if
290                  a TM is active.
291   Description: Sets the slave_sel bits in the core's CMD register.
292                they are used to choose which slave the core listens
293                to when performing a TM. The bits can't be set
294                during a TM, and the function will in such a case fail.
295*/
296int ASCS_input_select(int slave) {
297
298  if((slave < 0) || (slave > cfg->caps->nslaves)) {
299    /* Slave number is negative or too big */
300    DBG("ASCS_input_select: Wrong slave number\n");
301    return -GRASCS_ERROR_CAPFAULT;
302  }
303   
304  if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
305     RTEMS_SUCCESSFUL) {
306    /* Can't change active slave during a TM */
307    DBG("ASCS_input_select: Transaction active\n");
308    return -GRASCS_ERROR_TRANSACTIVE;
309  }
310 
311  cfg->regs->cmd = ((cfg->regs->cmd &= ~GRASCS_CMD_SLAVESEL) |
312                    (slave << GRASCS_CMD_SLAVESEL_BITS));
313
314  rtems_semaphore_release(cfg->tmsem1);
315  return 0;
316}
317
318/* Function: ASCS_etr_select
319   Arguments: src: The source of the ETR signal, valid values are
320                   0-GRASCS_MAX_TMS (0 = internal source, 1-GRASCS_MAX_TMS =
321                   external time markers 1-GRASCS_MAX_TMS).
322              freq: ETR frequency in Hz. Valid values are
323                    GRASCS_MIN_ETRFREQ-GRASCS_MAX_ETRFREQ
324   Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if src or freq values
325                  are invalid, -GRASCS_ERROR_STARTSTOP if synchronization interface
326                  isn't stopped.
327   Description: Changes the source for the ETR signal. The frequency of source signal
328                is assumed to be the same as the frequency of the freq input
329*/
330int ASCS_etr_select(int etr, int freq) {
331 
332  if((etr < 0) || (etr > GRASCS_MAX_TMS) || ((cfg->caps->tmconf == 0) && (etr > 0)) ||
333     (freq < GRASCS_MIN_ETRFREQ) || (freq > GRASCS_MAX_ETRFREQ)) {
334    /* ETR source value or frequency is invalid */
335    DBG("ASCS_etr_select: Wrong etr src number or wrong frequency\n");
336    return -GRASCS_ERROR_CAPFAULT;
337  }
338 
339  if(cfg->regs->sts & GRASCS_STS_ERUNNING) {
340    /* Synchronization interface is running */
341    DBG("ASCS_etr_select: Synch interface is running\n");
342    return -GRASCS_ERROR_STARTSTOP;
343  }
344 
345  cfg->regs->clk = ASCS_calc_clkreg(cfg->caps->clkfreq,freq);
346  cfg->regs->cmd = ((cfg->regs->cmd &= ~GRASCS_CMD_ETRCTRL) |
347                    (etr << GRASCS_CMD_ETRCTRL_BITS));
348
349  return 0;
350}
351
352/* Function: ASCS_start
353   Arguments: -
354   Return values: -
355   Description: Enables the serial interface.
356*/
357void ASCS_start(void) {
358 
359  /* Set register and internal status to running */
360  cfg->regs->cmd |= GRASCS_CMD_STARTSTOP;
361  cfg->running = 1;
362}
363
364/* Function: ASCS_stop
365   Arguments: -
366   Return values: -
367   Description: Disables the serial interface. This function will
368                block until possible calls to TC_send(_block) and
369                TM_recv(_block) has returned in order to be sure
370                that started transactions will be performed.
371*/
372void ASCS_stop(void) {
373
374  /* Set internal status to stopped */
375  cfg->running = 0;
376
377  /* Obtain semaphores to avoid possible situation where a
378     TC_send(_block) or TM_recv(_block) is aborted and driver is
379     waiting forever for an interrupt */
380  rtems_semaphore_obtain(cfg->tcsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
381  rtems_semaphore_obtain(cfg->tmsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
382
383  /* Change actual register value */
384  cfg->regs->cmd &= ~GRASCS_CMD_STARTSTOP;
385
386  /* Release the semaphores */
387  rtems_semaphore_release(cfg->tcsem1);
388  rtems_semaphore_release(cfg->tmsem1);
389}
390
391/* Function: ASCS_iface_status
392   Arguments: -
393   Return values: 0 if both serial interface and synch interface is stopped,
394                  1 if serial interface is running buth synch interface is
395                  stopped, 2 if serial interface is stopped but synch interface
396                  is running, 3 if both serial and synch interface is running
397   Description: Reads the core's STS register and reports the status of the
398                serial and synch interfaces
399*/
400int ASCS_iface_status(void) {
401
402  return ((cfg->regs->sts & 0x3) & (0x2 | cfg->running));
403}
404
405/* Function: ASCS_TC_send
406   Arguments: word: Pointer to a word that should be sent
407   Return values: 0 on success
408                  -GRASCS_ERROR_STARTSTOP if serial interface is stopped,
409                  -GRASCS_ERROR_TRANSACTIVE if another TC is in progress.
410   Description: Start a TC and sends the data that word points to.
411*/
412int ASCS_TC_send(int *word) {
413
414  int retval;
415
416  if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
417     RTEMS_SUCCESSFUL) {
418    /* Can't start a TC_send if another TC_send of TC_send_block is
419       in progress */
420    DBG("ASCS_TC_send: Could not obtain semaphore, transcation probably in progress\n");
421    return -GRASCS_ERROR_TRANSACTIVE;
422  }
423   
424  if(!cfg->running) {
425    /* Can't start a TC if serial interface isn't started */
426    DBG("ASCS_TC_send: Serial interface is not started\n");
427    retval = -GRASCS_ERROR_STARTSTOP;
428  }
429  else {
430    /* Start the transfer */
431    cfg->tcwords = 1;
432    if(cfg->caps->dbits == 8)
433      cfg->regs->tcd = *((unsigned char*)word);
434    else if(cfg->caps->dbits == 16)
435      cfg->regs->tcd = *((unsigned short int*)((int)word & ~1));
436    else
437      cfg->regs->tcd = *((unsigned int*)((int)word & ~3));
438   
439    /* Wait until transfer is complete */
440    rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
441    retval = 0;
442  }
443
444  rtems_semaphore_release(cfg->tcsem1);
445 
446  return retval;
447}
448
449/* Function: ASCS_TC_send_block
450   Arguments: block: Pointer to the start of a datablock that
451                     should be sent.
452              ntrans: Number of transfers needed to transfer
453                      the block.
454   Return values: 0 if successfull, -GRASCS_ERROR_STARTSTOP if TC
455                  couldn't be started because serial interface is
456                  stopped, -GRASCS_ERROR_TRANSACTIVE if TC couldn't
457                  be started because another TC isn't done yet.
458   Description: Starts ntrans TCs and sends the data that starts at the
459                address that block points to. The size of each
460                transaction will vary depending on whether the core is
461                configured for 8, 16, or 32 bits data transfers.
462*/
463int ASCS_TC_send_block(int *block, int ntrans) {
464
465  int retval;
466
467  if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
468     RTEMS_SUCCESSFUL) {
469    /* Can't start a TC_send_block if another TC_send of TC_send_block is
470       in progress */
471    DBG("ASCS_TC_send_block: Could not obtain semaphore, transcation probably in progress\n");
472    return -GRASCS_ERROR_TRANSACTIVE;
473  }
474
475  if(!cfg->running) {
476    /* Can't start a TC if serial interface isn't started */
477    DBG("ASCS_TC_send_block: Serial interface is not started\n");
478    retval = -GRASCS_ERROR_STARTSTOP;
479  }
480  else {
481    /* Start the first transfer */
482    cfg->tcwords = ntrans;
483    if(cfg->caps->dbits == 8) {
484      cfg->tcptr = (int)block;
485      cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
486    }
487    else if(cfg->caps->dbits == 16) {
488      cfg->tcptr = (int)block & ~1;
489      cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
490    }
491    else {
492      cfg->tcptr = (int)block & ~3;
493      cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
494    }
495       
496    /* Wait until all transfers are complete */
497    rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
498    retval = 0;
499  }
500 
501  rtems_semaphore_release(cfg->tcsem1);
502
503  return retval;
504}
505
506/* Function: ASCS_TC_sync_start
507   Arguments: -
508   Return values: -
509   Description: Starts synchronization interface. Might
510     be delayed if a TM is in progress. SW can poll
511     ASCS_iface_status() to find out when synch interface is
512     started. First ETR pulse can be delay up to one ETR
513     period depending on the source of the ETR and
514     activity on the TM line.
515*/
516void ASCS_TC_sync_start(void) {
517 
518  cfg->regs->cmd |= GRASCS_CMD_ESTARTSTOP;
519}
520
521/* Function: ASCS_TC_sync_stop
522   Arguments: -
523   Return values: -
524   Description: Stops the synchronization interface. Might
525     be delayed for 1 us if a ETR pulse is being generated. SW
526     can determine when synch interface has stopped by polling
527     ASCS_iface_status().
528*/
529void ASCS_TC_sync_stop(void) {
530 
531  cfg->regs->cmd &= ~GRASCS_CMD_ESTARTSTOP;
532}
533
534/* Function: ASCS_TM_recv
535   Arguments: word: Pointer to where the received word should be
536                    placed
537   Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
538                  interface isn't started, -GRASCS_ERROR_TRANSACTIVE
539                  if another TM is in progress
540   Description: Starts a TM and stores the incoming data in word.
541*/
542int ASCS_TM_recv(int *word) {
543
544  int retval;
545
546  if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
547     RTEMS_SUCCESSFUL) {
548    /* Can't start a TM_recv if another TM_recv of TM_recv_block is
549       in progress */
550    DBG("ASCS_TM_recv: Could not obtain semaphore, transaction probably in progress\n");
551    return -GRASCS_ERROR_TRANSACTIVE;
552  }
553
554  if(!cfg->running) {
555    /* Can't start a TM if serial interface isn't started */
556    DBG("ASCS_TM_recv: Serial interface is not started\n");
557    retval = -GRASCS_ERROR_STARTSTOP;
558  }
559  else {
560    /* Start transfer */
561    cfg->tmwords = 1;
562    cfg->tmptr = (int)word;
563    cfg->regs->cmd |= GRASCS_CMD_SENDTM;
564   
565    /* Wait until transfer finishes */
566    rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
567    retval = 0;
568  }
569
570  rtems_semaphore_release(cfg->tmsem1);
571
572  return retval;
573}
574
575/* Function: ASCS_TM_recv_block
576   Arguments: block: Pointer to where the received datablock
577                     should be stored.
578              ntrans: Number of transfers needed to transfer
579                      the block.
580   Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
581                  interface isn't started, -GRASCS_ERROR_TRANSACTIVE if
582                  a performed TM hasn't been processed yet
583   Description: Starts ntrans TMs and stores the data at the address
584                that block points to. The size of each transaction
585                will vary depending on whether the core is
586                configured for 8, 16, or 32 bits data transfers.
587*/
588int ASCS_TM_recv_block(int *block, int ntrans) {
589
590  int retval;
591
592  if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
593     RTEMS_SUCCESSFUL) {
594    /* Can't start a TM_recv_block if another TM_recv of TM_recv_block is
595       in progress */
596    DBG("ASCS_TM_recv_block: Could not obtain semaphore, transaction probably in progress\n");
597    return -GRASCS_ERROR_TRANSACTIVE;
598  }
599
600  if(!cfg->running) {
601    /* Can't start a TM if serial interface isn't started */
602    DBG("ASCS_TM_recv_block: Serial interface is not started\n");
603    retval = -GRASCS_ERROR_STARTSTOP;
604  }
605  else {
606    /* Start transfer */
607    cfg->tmwords = ntrans;
608    cfg->tmptr = (int)block;
609    cfg->regs->cmd |= GRASCS_CMD_SENDTM;
610   
611    /* Wait until transfer finishes */
612    rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
613    retval = 0;
614  }
615
616  rtems_semaphore_release(cfg->tmsem1);
617
618  return retval;
619}
Note: See TracBrowser for help on using the repository browser.