source: rtems/c/src/lib/libbsp/sparc/shared/ascs/grascs.c @ 4a7d1026

4.115
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 08:25:52

sparc bsps: updated license to rtems.org

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