Project

General

Profile

Download (22.5 KB) Statistics
| Branch: | Tag: | Revision:
1
/* AT91SAM7 SSC controller routines for OpenPICC
2
 * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
3
 * (C) 2007-2008 Henryk Plötz <henryk@ploetzli.ch>
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by 
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 * We use SSC for both TX and RX side.
20
 *
21
 * RX side is interconnected with demodulated carrier 
22
 *
23
 * TX side is interconnected with load modulation circuitry
24
 */
25

    
26
#include <FreeRTOS.h>
27
#include <queue.h>
28
#include <task.h>
29
#include <openpicc.h>
30

    
31
#include <string.h>
32
#include <errno.h>
33

    
34
#include "ssc.h"
35
#include "iso14443.h"
36

    
37
#include "clock_switch.h"
38
#include "tc_cdiv_sync.h"
39
#include "tc_fdt.h"
40
#include "led.h"
41

    
42
#include "usb_print.h"
43
#include "cmd.h"
44

    
45
#define PRINT_DEBUG 0
46
#define DEBUG_DATA_GATING 0
47

    
48
struct _ssc_handle {
49
	enum ssc_mode mode;
50
	const struct openpicc_hardware *openpicc;
51
	ssc_dma_rx_buffer_t* rx_buffer[2];
52
	ssc_dma_tx_buffer_t* tx_buffer;
53
	ssc_callback_t callback;
54
	xQueueHandle rx_queue;
55
	AT91PS_PDC pdc;
56
	AT91PS_SSC ssc;
57
	u_int8_t rx_enabled, tx_enabled;
58
	u_int8_t rx_running, tx_running, tx_need_switching;
59
};
60

    
61
static ssc_handle_t _ssc;
62
static const ssc_mode_def ssc_modes[] = {
63
	/* Undefined, no size set */
64
	[SSC_MODE_NONE]		   = {SSC_MODE_NONE, 0, 0, 0},
65
	/* 14443A Frame */
66
	[SSC_MODE_14443A]      = {SSC_MODE_14443A, 
67
		ISO14443_BITS_PER_SSC_TRANSFER * ISO14443A_SAMPLE_LEN,               // transfersize_ssc 
68
		ISO14443_BITS_PER_SSC_TRANSFER * ISO14443A_SAMPLE_LEN <= 8 ? 8 : 16, // transfersize_pdc 
69
		DIV_ROUND_UP(ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS, ISO14443_BITS_PER_SSC_TRANSFER) },
70
};
71
static struct {
72
	ssc_metric metric;
73
	char *name;
74
	int value;
75
} ssc_metrics[] = {
76
		[METRIC_RX_OVERFLOWS]      = {METRIC_RX_OVERFLOWS, "Rx overflows", 0},
77
		[METRIC_FREE_RX_BUFFERS]   = {METRIC_FREE_RX_BUFFERS, "Free Rx buffers", 0},
78
		[METRIC_MANAGEMENT_ERRORS] = {METRIC_MANAGEMENT_ERRORS, "Internal buffer management error", 0},
79
		[METRIC_MANAGEMENT_ERRORS_1] = {METRIC_MANAGEMENT_ERRORS_1, "Internal buffer management error type 1", 0},
80
		[METRIC_MANAGEMENT_ERRORS_2] = {METRIC_MANAGEMENT_ERRORS_2, "Internal buffer management error type 2", 0},
81
		[METRIC_MANAGEMENT_ERRORS_3] = {METRIC_MANAGEMENT_ERRORS_3, "Internal buffer management error type 3", 0},
82
		[METRIC_LATE_TX_FRAMES]    = {METRIC_LATE_TX_FRAMES, "Late Tx frames", 0},
83
		[METRIC_RX_FRAMES]         = {METRIC_RX_FRAMES, "Rx frames", 0},
84
		[METRIC_TX_FRAMES]         = {METRIC_TX_FRAMES, "Tx frames", 0},
85
		[METRIC_TX_ABORTED_FRAMES] = {METRIC_TX_ABORTED_FRAMES, "Aborted Tx frames", 0},
86
};
87

    
88
static ssc_dma_rx_buffer_t _rx_buffers[SSC_DMA_BUFFER_COUNT];
89
ssc_dma_tx_buffer_t        _tx_buffer;
90

    
91
/******* PRIVATE "meat" code *************************************************/
92

    
93
#define SSC_RX_IRQ_MASK	(AT91C_SSC_RXRDY | 	\
94
			 AT91C_SSC_OVRUN | 	\
95
			 AT91C_SSC_ENDRX |	\
96
			 AT91C_SSC_RXBUFF |	\
97
			 AT91C_SSC_RXSYN |	\
98
			 AT91C_SSC_CP0 |	\
99
			 AT91C_SSC_CP1)
100

    
101
#define SSC_TX_IRQ_MASK (AT91C_SSC_TXRDY |	\
102
			 AT91C_SSC_TXEMPTY | 	\
103
			 AT91C_SSC_ENDTX |	\
104
			 AT91C_SSC_TXBUFE |	\
105
			 AT91C_SSC_TXSYN)
106

    
107
static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh);
108
static __ramfunc int _reload_rx(ssc_handle_t *sh);
109

    
110

    
111
static int __ramfunc _ssc_rx_irq(u_int32_t orig_sr, int start_asserted, portBASE_TYPE task_woken)
112
{
113
	int end_asserted = 0;
114
	ssc_handle_t *sh = &_ssc;
115
	u_int32_t orig_rcmr = sh->ssc->SSC_RCMR;
116
	
117
#if PRINT_DEBUG
118
	int old = usb_print_set_default_flush(0);  // DEBUG OUTPUT
119
	DumpStringToUSB("orig:");  // DEBUG OUTPUT
120
	DumpUIntToUSB(orig_sr);  // DEBUG OUTPUT
121
	DumpStringToUSB("\n\r");  // DEBUG OUTPUT
122
#endif
123
	u_int32_t sr = orig_sr | _ssc.ssc->SSC_SR;
124
	
125
	if( (sr & AT91C_SSC_RXSYN) || start_asserted) {
126
		sh->ssc->SSC_RCMR = (orig_rcmr & (~AT91C_SSC_START)) | (AT91C_SSC_START_CONTINOUS);
127
		/* Receiving has started */
128
		if(sh->callback != NULL) {
129
			sh->callback(SSC_CALLBACK_RX_FRAME_BEGIN, &end_asserted);
130
			if(end_asserted)
131
				sr = orig_sr | _ssc.ssc->SSC_SR;
132
		}
133
	}
134
	
135
#if PRINT_DEBUG	
136
	DumpStringToUSB("sr:");  // DEBUG OUTPUT
137
	DumpUIntToUSB(sr);  // DEBUG OUTPUT
138
	DumpStringToUSB("\n\r");  // DEBUG OUTPUT
139
	usb_print_set_default_flush(old);  // DEBUG OUTPUT
140
#endif
141
	
142
	if(((sr & (AT91C_SSC_CP1 | AT91C_SSC_ENDRX)) || end_asserted) && (sh->rx_buffer[0] != NULL)) {
143
		/* Receiving has ended */
144
		AT91F_PDC_DisableRx(sh->pdc);
145
		AT91F_SSC_DisableRx(sh->ssc);
146
		sh->ssc->SSC_RCMR = ((sh->ssc->SSC_RCMR) & (~AT91C_SSC_START)) | (AT91C_SSC_START_0);
147

    
148
		ssc_dma_rx_buffer_t *buffer = _unload_rx(sh);
149
		if(buffer != NULL) {
150
			if(sh->callback != NULL)
151
				sh->callback(SSC_CALLBACK_RX_FRAME_ENDED, buffer);
152

    
153
			if(buffer->state != SSC_FREE) {
154
				task_woken = xQueueSendFromISR(sh->rx_queue, &buffer, task_woken);
155
			}
156
		}
157
		
158
		if(_reload_rx(sh)) {
159
			/* Clear the receive holding register. Is this necessary? */
160
			int dummy = sh->ssc->SSC_RHR; (void)dummy;
161
			AT91F_PDC_EnableRx(sh->pdc);
162
			if(!sh->tx_running) {
163
				/* Only start the receiver if no Tx has been started. Warning: Need
164
				 * to make sure that the receiver is restarted again when the Tx is over.
165
				 * Note that this is only necessary when not using Compare 0 to start
166
				 * reception. When using Compare 0 the data gating mechanism will keep
167
				 * CP0 from happening and thus keep the receiver stopped.
168
				 *
169
				 * Note also that we're not resetting rx_running to 0, because conceptionally
170
				 * the Rx is still running,. So rx_running=1 and tx_running=1 means SSC_RX
171
				 * stopped and SSC_RX should be started as soon as SSC_TX stops.
172
				 */
173
				AT91F_SSC_EnableRx(sh->ssc);
174
			}
175
		} else {
176
			sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK;
177
			sh->rx_running = 0;
178
			sh->callback(SSC_CALLBACK_RX_STOPPED, sh);
179
		}
180
		
181
	}
182

    
183
	sh->ssc->SSC_RCMR = orig_rcmr;
184
	return task_woken;
185
}
186

    
187
/* Exported callback for the case when the frame start has been detected externally */
188
void ssc_frame_started(void)
189
{
190
	_ssc_rx_irq(_ssc.ssc->SSC_SR, 1, pdFALSE);
191
}
192

    
193
static void __ramfunc _ssc_tx_end(ssc_handle_t *sh, int is_an_abort)
194
{
195
	AT91F_PDC_DisableTx(sh->pdc);
196
	AT91F_SSC_DisableTx(sh->ssc);
197
	sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
198
	
199
	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_TF, 0);
200
	usb_print_string_f(">",0);
201
	
202
	AT91F_PDC_SetTx(sh->pdc, 0, 0);
203
	AT91F_PDC_SetNextTx(sh->pdc, 0, 0);
204

    
205
	if(sh->tx_buffer) {
206
		sh->tx_buffer->state = SSC_FREE;
207
		sh->tx_running = 0;
208
	}
209
	
210
	if(sh->rx_running) {
211
		/* Receiver has been suspended by the pending transmission. Restart it. */
212
		AT91F_SSC_EnableRx(sh->ssc);
213
	}
214
	
215
	if(sh->callback) {
216
		if(is_an_abort)
217
			sh->callback(SSC_CALLBACK_TX_FRAME_ABORTED, sh->tx_buffer);
218
		else
219
			sh->callback(SSC_CALLBACK_TX_FRAME_ENDED, sh->tx_buffer);
220
	}
221
		
222
	sh->tx_buffer = NULL;
223
}
224

    
225
static int __ramfunc _ssc_tx_irq(u_int32_t sr, portBASE_TYPE task_woken)
226
{
227
	ssc_handle_t *sh = &_ssc;
228
	
229
	if( sr & AT91C_SSC_TXSYN ) {
230
		/* Tx starting, hardwire TF pin to high */
231
		AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PA15_TF);
232
		AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PA15_TF);
233
		usb_print_string_f("<",0);
234
		
235
		/* Also set SSC mode to continous 
236
		 * FIXME BUG: This will somehow add two samples on the SSC 
237
		 * The abomination below is designed to find a pause in the outgoing modulation data
238
		 * (WARNING: Will only work with manchester, not with PSK) so that the SSC start type
239
		 * switch will happen during a time of no subcarrier modulation (in order to not
240
		 * upset the subcarrier). Still need to find a way to 'absorb' the extra two samples. */
241
		if(sh->tx_need_switching) {
242
			vLedSetGreen(0);
243
			int j = 0;
244
off_pre:
245
			if(j++ > 100) goto out;
246
			if(!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_MOD_PWM)) {
247
				goto off_pre;
248
			}
249
on:
250
			if(j++ > 100) goto out;
251
			if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_MOD_PWM)) goto on;
252
			int i=0;
253
off:
254
			if(j++ > 100) goto out;
255
			if(!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_MOD_PWM)) {
256
				if(i++ > 2) goto out; else goto off;
257
			} else goto on;
258
out:
259
			sh->ssc->SSC_TCMR = (sh->ssc->SSC_TCMR & ~AT91C_SSC_START) | AT91C_SSC_START_CONTINOUS;
260
			vLedSetGreen(1);
261
		}
262

    
263
		if(sh->callback) 
264
			sh->callback(SSC_CALLBACK_TX_FRAME_BEGIN, NULL);
265
	}
266
	
267
	if( sr & AT91C_SSC_TXEMPTY ) {
268
		/* Tx has ended */
269
		ssc_metrics[METRIC_TX_FRAMES].value++;
270
		_ssc_tx_end(sh, 0);
271
	}
272
	
273
	return task_woken;
274
}
275

    
276
static void __ramfunc ssc_irq(void) __attribute__ ((naked));
277
static void __ramfunc ssc_irq(void)
278
{
279
	portENTER_SWITCHING_ISR();
280
	vLedSetRed(1);
281
	portBASE_TYPE task_woken = pdFALSE;
282
	
283
	u_int32_t sr = _ssc.ssc->SSC_SR;
284
	if(sr & AT91C_SSC_RXSYN) {
285
		task_woken = _ssc_rx_irq(sr, 1, task_woken);
286
	} else if(sr & SSC_RX_IRQ_MASK) {
287
		task_woken = _ssc_rx_irq(sr, 0, task_woken);
288
	}
289
	
290
	if(sr & SSC_TX_IRQ_MASK) {
291
		task_woken = _ssc_tx_irq(sr, task_woken);
292
	}
293
	
294
	AT91F_AIC_ClearIt(AT91C_ID_SSC);
295
	AT91F_AIC_AcknowledgeIt();
296

    
297
	vLedSetRed(0);
298
	portEXIT_SWITCHING_ISR(task_woken);
299
}
300

    
301
static __ramfunc ssc_dma_rx_buffer_t *_get_buffer(ssc_dma_buffer_state_t old, ssc_dma_buffer_state_t new)
302
{
303
	ssc_dma_rx_buffer_t *buffer = NULL;
304
	int i;
305
	for(i=0; i < SSC_DMA_BUFFER_COUNT; i++) {
306
		if(_rx_buffers[i].state == old) {
307
			buffer = &_rx_buffers[i];
308
			buffer->state = new;
309
			break;
310
		}
311
	}
312
	return buffer;
313
}
314

    
315
/* Doesn't check sh, must be called with interrupts disabled */
316
static __ramfunc int _reload_rx(ssc_handle_t *sh)
317
{
318
	int result = 0;
319
	if(sh->rx_buffer[0] != NULL) {
320
		ssc_metrics[METRIC_MANAGEMENT_ERRORS_1].value++;
321
		result = 1;
322
		goto out;
323
	}
324
	
325
	ssc_dma_rx_buffer_t *buffer = _get_buffer(SSC_FREE, SSC_PENDING);
326
	
327
	if(buffer == NULL) {
328
		ssc_metrics[METRIC_RX_OVERFLOWS].value++;
329
		goto out;
330
	}
331

    
332
	buffer->reception_mode = &ssc_modes[sh->mode];
333
	buffer->len_transfers = ssc_modes[sh->mode].transfers;
334
	
335
	AT91F_PDC_SetRx(sh->pdc, buffer->data, buffer->len_transfers);
336
	sh->rx_buffer[0] = buffer;
337
	
338
	result = 1;
339
out:
340
	return result;
341
}
342

    
343
// Doesn't check sh, call with interrupts disabled, SSC/PDC stopped
344
static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh)
345
{
346
	if(sh->rx_buffer[0] == NULL) {
347
		ssc_metrics[METRIC_MANAGEMENT_ERRORS_2].value++;
348
		return NULL;
349
	}
350
	
351
	ssc_dma_rx_buffer_t *buffer = sh->rx_buffer[0];
352
	u_int32_t rpr = sh->pdc->PDC_RPR, 
353
		rcr = sh->pdc->PDC_RCR;
354
	AT91F_PDC_SetRx(sh->pdc, 0, 0);
355
	sh->rx_buffer[0] = NULL;
356
	buffer->state = SSC_FULL;
357
	
358
	if(rcr == 0) {
359
		buffer->flags.overflow = 1;
360
	} else {
361
		buffer->flags.overflow = 0;
362
	}
363
	
364
	if(rcr > 0) {
365
		/* Append a zero to make sure the buffer decoder finds the stop bit */
366
		switch(buffer->reception_mode->transfersize_pdc) {
367
		case 8:
368
			//*((u_int8_t*)rpr++) = sh->ssc->SSC_RSHR;
369
			*((u_int8_t*)rpr++) = 0;
370
			--rcr;
371
			break;
372
		case 16:
373
			*((u_int16_t*)rpr++) = 0;
374
			--rcr;
375
			break;
376
		case 32:
377
			*((u_int32_t*)rpr++) = 0;
378
			--rcr;
379
			break;
380
		}
381
	}
382
	
383
	if((buffer->len_transfers - rcr) != (rpr - (unsigned int)buffer->data)*(buffer->reception_mode->transfersize_pdc/8)) {
384
		ssc_metrics[METRIC_MANAGEMENT_ERRORS_3].value++;
385
		buffer->state = SSC_FREE;
386
		return NULL;
387
	}
388
	
389
	buffer->len_transfers = buffer->len_transfers - rcr;
390
	
391
	return buffer;
392
}
393

    
394
void ssc_set_gate(int data_enabled) {
395
	if(OPENPICC->features.data_gating) {
396
		if(data_enabled) {
397
			AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE);
398
			if(DEBUG_DATA_GATING) usb_print_string_f("(", 0);
399
		} else {
400
			AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE);
401
			if(DEBUG_DATA_GATING) usb_print_string_f(")", 0);
402
		}
403
	}
404
}
405

    
406
static void _ssc_start_rx(ssc_handle_t *sh)
407
{
408
	taskENTER_CRITICAL();
409
	if(sh != &_ssc) goto out;
410
	if(sh->rx_running) goto out;
411
	if(!sh->rx_enabled) goto out;
412

    
413
	// Load buffer
414
	if(!_reload_rx(sh))
415
		goto out;
416
	
417
	sh->ssc->SSC_IER = AT91C_SSC_RXSYN | \
418
		 AT91C_SSC_CP1 | AT91C_SSC_ENDRX;
419
	sh->rx_running = 1;
420
	if(sh->callback != NULL)
421
		sh->callback(SSC_CALLBACK_RX_STARTING, sh);
422

    
423
	// Actually enable reception
424
	int dummy = sh->ssc->SSC_RHR; (void)dummy;
425
	AT91F_PDC_EnableRx(sh->pdc);
426
	AT91F_SSC_EnableRx(sh->ssc);
427

    
428
out:
429
	taskEXIT_CRITICAL();
430
	usb_print_string_f(sh->rx_running ? "SSC now running\n\r":"SSC not running\n\r", 0);
431
}
432

    
433
static void _ssc_stop_rx(ssc_handle_t *sh)
434
{
435
	taskENTER_CRITICAL();
436
	sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK;
437
	sh->rx_running = 0;
438
	if(sh->callback != NULL)
439
		sh->callback(SSC_CALLBACK_RX_STOPPED, sh);
440
	taskEXIT_CRITICAL();
441
}
442

    
443
/******* PRIVATE Initialization Code *****************************************/
444
static void _ssc_rx_mode_set(ssc_handle_t *sh, enum ssc_mode ssc_mode)
445
{
446
	taskENTER_CRITICAL();
447
	int was_running = sh->rx_running;
448
	if(was_running) _ssc_stop_rx(sh);
449

    
450
	u_int8_t data_len=0, num_data=0, sync_len=0;
451
	u_int32_t start_cond=0;
452
	u_int32_t clock_gating=0;
453
	u_int8_t stop = 0, invert=0;
454

    
455
	switch(ssc_mode) {
456
		case SSC_MODE_14443A:
457
			/* Start on Compare 0. The funky calculations down there are designed to allow a different
458
			 * (longer) compare length for Compare 1 than for Compare 0. Both lengths are set by the
459
			 * same register. */
460
			start_cond = AT91C_SSC_START_0;
461
			sync_len = ISO14443A_EOF_LEN;
462
			sh->ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE << (ISO14443A_EOF_LEN-ISO14443A_SOF_LEN);
463
			sh->ssc->SSC_RC1R = ISO14443A_EOF_SAMPLE;
464
			
465
			data_len = ssc_modes[SSC_MODE_14443A].transfersize_ssc;
466
			
467
			/* We are using stop on Compare 1. The docs are ambiguous but my interpretation is that
468
			 * this means that num_data is basically ignored and reception is continuous until stop
469
			 * event. Set num_data to the maximum anyways. */
470
			num_data = 16;
471
			stop = 1;
472
			
473
			stop = 0;
474
			start_cond = AT91C_SSC_START_CONTINOUS;
475
			sync_len = 0;
476
			
477
			/* We can't use receive clock gating with RF because RF will only go up with the first
478
			 * edge, this doesn't cooperate with the longer sync len above. 
479
			 * FIXME: What's the interaction between clock BURST on v0.4p1, RF and Compare 0? 
480
			 * In theory this shouldn't work even without SSC clock_gating because BURST gates the
481
			 * clock before the SSC and so it shouldn't get sync_len samples before Compare 0. 
482
			 * I believe there's a bug waiting to happen somewhere here. */
483
			clock_gating = (0x0 << 6);
484
			//invert = AT91C_SSC_CKI;
485
			break;
486
		case SSC_MODE_NONE:
487
			goto out;
488
			break;
489
	}
490
	
491
	/* Receive frame mode register */
492
	sh->ssc->SSC_RFMR = ((data_len-1) & 0x1f) |
493
			(((num_data-1) & 0x0f) << 8) | 
494
			(((sync_len-1) & 0x0f) << 16);
495
	
496
	/* Receive clock mode register, Clock selection: RK, Clock output: None */
497
	sh->ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | 
498
			clock_gating | invert | start_cond | (stop << 12);
499

    
500
out:
501
	sh->mode = ssc_mode;
502
	if(was_running) _ssc_start_rx(sh);
503
	taskEXIT_CRITICAL();
504
}
505

    
506
#if SSC_DMA_BUFFER_COUNT > 0
507
static inline int _init_ssc_rx(ssc_handle_t *sh)
508
{
509
	tc_cdiv_sync_init();
510
	tc_cdiv_sync_enable();
511
	
512
	if(sh->rx_queue == NULL) {
513
		sh->rx_queue = xQueueCreate(10, sizeof(sh->rx_buffer[0]));
514
		if(sh->rx_queue == NULL)
515
			goto out_fail_queue;
516
	}
517
	
518
	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 
519
			    OPENPICC_SSC_DATA | OPENPICC_SSC_CLOCK |
520
			    OPENPICC_PIO_FRAME,
521
			    0);
522
	
523
	/* FIXME: This is handled by tc_cdiv_sync and shouldn't be necessary */
524
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL);
525
	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL);
526
	
527
	if(OPENPICC->features.clock_switching) {
528
		AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH);
529
		clock_switch(CLOCK_SELECT_PLL);
530
	}
531

    
532
	/* Disable all interrupts */
533
	sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK;
534

    
535
	/* don't divide clock inside SSC, we do that in tc_cdiv */
536
	sh->ssc->SSC_CMR = 0;
537

    
538
	unsigned int i;
539
	for(i=0; i<sizeof(_rx_buffers)/sizeof(_rx_buffers[0]); i++)
540
		memset(&_rx_buffers[i], 0, sizeof(_rx_buffers[i]));
541
	
542
	sh->rx_buffer[0] = sh->rx_buffer[1] = NULL;
543
	
544
	/* Will be set to a real value some time later 
545
	 * FIXME Layering? */
546
	tc_fdt_set(0xff00);
547
	
548
	return 1;
549
	
550
out_fail_queue:
551
	return 0;
552
}
553
#endif
554

    
555
static inline int _init_ssc_tx(ssc_handle_t *sh)
556
{
557
	/* IMPORTANT: Disable PA23 (PWM0) output, since it is connected to 
558
	 * PA17 !! */
559
	AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_MOD_PWM);
560
	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, OPENPICC_MOD_SSC | 
561
			    OPENPICC_SSC_CLOCK | OPENPICC_SSC_TF, 0);
562
	
563
	if(OPENPICC->features.clock_switching) {
564
		clock_switch_init();
565
		/* Users: remember to clock_switch(CLOCK_SELECT_CARRIER) as
566
		 * early as possible, e.g. right after receive end */
567
	}
568

    
569
	/* Disable all interrupts */
570
	sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
571

    
572
	/* don't divide clock inside SSC, we do that in tc_cdiv */
573
	sh->ssc->SSC_CMR = 0;
574

    
575
	return 1;
576
}
577

    
578
static int _ssc_register_callback(ssc_handle_t *sh, ssc_callback_t _callback)
579
{
580
	if(!sh) return -EINVAL;
581
	if(sh->callback != NULL) return -EBUSY;
582
	sh->callback = _callback;
583
	if(sh->callback != NULL) 
584
		sh->callback(SSC_CALLBACK_SETUP, sh);
585
	return 0;
586
}
587

    
588
static int _ssc_unregister_callback(ssc_handle_t *sh, ssc_callback_t _callback)
589
{
590
	if(!sh) return -EINVAL;
591
	if(_callback == NULL || sh->callback == _callback) {
592
		if(sh->callback != NULL) 
593
			sh->callback(SSC_CALLBACK_TEARDOWN, sh);
594
		sh->callback = NULL;
595
	}
596
	return 0;
597
}
598

    
599
/******* PUBLIC API **********************************************************/
600
ssc_handle_t* ssc_open(u_int8_t init_rx, u_int8_t init_tx, enum ssc_mode mode, ssc_callback_t callback)
601
{
602
	ssc_handle_t *sh = &_ssc;
603
	
604
	if(sh->rx_enabled || sh->tx_enabled || sh->rx_running) {
605
		if( ssc_close(sh) != 0) {
606
			return NULL;
607
		}
608
	}
609
	
610
	if(init_rx || init_tx) {
611
		sh->ssc = AT91C_BASE_SSC;
612
		sh->pdc = (AT91PS_PDC) &(sh->ssc->SSC_RPR);
613

    
614
		AT91F_SSC_CfgPMC();
615

    
616
		if(OPENPICC->features.data_gating) {
617
			AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE);
618
			ssc_set_gate(1);
619
		}
620
	}
621
	
622

    
623
	if(init_tx) {
624
		sh->tx_enabled = _init_ssc_tx(sh);
625
		if(!sh->tx_enabled) {
626
			ssc_close(sh);
627
			return NULL;
628
		}
629
	}
630
	
631
	if(init_rx) {
632
#if SSC_DMA_BUFFER_COUNT > 0
633
		sh->rx_enabled = _init_ssc_rx(sh);
634
		if(!sh->rx_enabled) {
635
			ssc_close(sh);
636
			return NULL;
637
		}
638
#else
639
		ssc_close(sh);
640
		return NULL;
641
#endif
642
	}
643
	
644
	if(sh->rx_enabled || sh->tx_enabled) {
645
		_ssc_rx_mode_set(sh, mode);
646
		AT91F_AIC_ConfigureIt(AT91C_ID_SSC,
647
				      OPENPICC_IRQ_PRIO_SSC,
648
				      AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&ssc_irq);
649
				      //AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, (THandler)&ssc_irq);
650
		AT91F_AIC_EnableIt(AT91C_ID_SSC);
651
	}
652
	
653
	if(callback != NULL)
654
		_ssc_register_callback(sh, callback);
655
	
656
	if(init_rx)
657
		_ssc_start_rx(sh);
658
	
659
	return sh;
660
}
661

    
662
int ssc_recv(ssc_handle_t* sh, ssc_dma_rx_buffer_t* *buffer,unsigned int timeout)
663
{
664
	if(sh == NULL) return -EINVAL;
665
	if(!sh->rx_enabled) return -EINVAL;
666
	
667
	taskENTER_CRITICAL();
668
	if(sh->rx_running) {
669
		if(PRINT_DEBUG) usb_print_string_f("Continuing SSC Rx\n\r",0); // DEBUG OUTPUT
670
	} else {
671
		if(PRINT_DEBUG) usb_print_string_f("ERR: SSC halted\n\r",0); // DEBUG OUTPUT
672
		/* Try starting the Reception */
673
		_ssc_start_rx(sh);
674
	}
675
	taskEXIT_CRITICAL();
676
	
677
	if(xQueueReceive(sh->rx_queue, buffer, timeout)){
678
		if(*buffer != NULL) return 0;
679
		else return -EINTR;
680
	}
681
	
682
	return -ETIMEDOUT;
683
}
684
extern u_int32_t fdt_offset;
685
/* Must be called with IRQs disabled. E.g. from IRQ context or within a critical section. */
686
int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t *buffer)
687
{
688
	if(sh == NULL) return -EINVAL;
689
	if(!sh->tx_enabled) return -EINVAL;
690
	if(sh->tx_running) return -EBUSY;
691
	
692
	sh->tx_buffer = buffer;
693
	sh->tx_running = 1;
694
	
695
	/* disable Tx */
696
	sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
697
	AT91F_PDC_DisableTx(sh->pdc);
698
	AT91F_SSC_DisableTx(sh->ssc);
699

    
700
	int start_cond = AT91C_SSC_START_HIGH_RF;
701
	
702
	int sync_len = 1;
703
	int data_len = 32;
704
	int num_data = buffer->len/(data_len/8); /* FIXME This is broken for more than 64 bytes, or is it? */
705
	int num_data_ssc = num_data > 16 ? 16 : num_data;
706
	sh->tx_need_switching = (num_data > 16);
707
	
708
	sh->ssc->SSC_TFMR = ((data_len-1) & 0x1f) |
709
			(((num_data_ssc-1) & 0x0f) << 8) | 
710
			(((sync_len-1) & 0x0f) << 16);
711
	sh->ssc->SSC_TCMR = 0x01 | AT91C_SSC_CKO_NONE | (AT91C_SSC_CKI&0) | start_cond;
712
	
713
	AT91F_PDC_SetTx(sh->pdc, buffer->data, num_data);
714
	AT91F_PDC_SetNextTx(sh->pdc, 0, 0);
715
	buffer->state = SSC_PENDING;
716

    
717
	sh->ssc->SSC_IER = AT91C_SSC_TXEMPTY | AT91C_SSC_TXSYN;
718
	/* Enable DMA */
719
	sh->ssc->SSC_THR = 0;
720
	AT91F_PDC_EnableTx(sh->pdc);
721
	
722
	/* Disable Receiver, see comments in _ssc_rx_irq */
723
	AT91F_SSC_DisableRx(sh->ssc);
724
	/* Start Transmission */
725
	AT91F_SSC_EnableTx(sh->ssc);
726
	vLedSetGreen(1);
727
	
728
	if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_SSC_TF)) {
729
		ssc_metrics[METRIC_LATE_TX_FRAMES].value++;
730
	}
731
	
732
	return 0;
733
}
734

    
735
int ssc_send_abort(ssc_handle_t* sh)
736
{
737
	if(!sh) return -EINVAL;
738
	if(!sh->tx_enabled) return -EINVAL;
739
	if(!sh->tx_running) return -EINVAL;
740
	
741
	ssc_metrics[METRIC_TX_ABORTED_FRAMES].value++;
742
	_ssc_tx_end(sh, 1);
743
	
744
	return 0;
745
}
746

    
747
int ssc_close(ssc_handle_t* sh)
748
{
749
	if(sh->rx_running)
750
		_ssc_stop_rx(sh);
751
	
752
	if(sh->rx_enabled) {
753
		// FIXME Implement
754
		sh->rx_enabled = 0;
755
	}
756
	if(sh->tx_enabled) {
757
		// FIXME Implement
758
		sh->tx_enabled = 0;
759
	}
760
	
761
	_ssc_unregister_callback(sh, NULL);
762
	return 0;
763
}
764

    
765
/* Hard reset the SSC to flush all buffers and whatnot. Call with IRQs disabled */ 
766
void ssc_hard_reset(ssc_handle_t *sh)
767
{
768
	if(sh == NULL) return;
769
	if(!sh->rx_enabled && !sh->tx_enabled) return;
770
	
771
	u_int32_t
772
		cmr = sh->ssc->SSC_CMR,
773
		rcmr = sh->ssc->SSC_RCMR,
774
		rfmr = sh->ssc->SSC_RFMR,
775
		tcmr = sh->ssc->SSC_TCMR,
776
		tfmr = sh->ssc->SSC_TFMR,
777
		rc0r = sh->ssc->SSC_RC0R,
778
		rc1r = sh->ssc->SSC_RC1R,
779
		sr = sh->ssc->SSC_SR,
780
		imr = sh->ssc->SSC_IMR;
781
	
782
	sh->ssc->SSC_CR = AT91C_SSC_SWRST;
783
	
784
	sh->ssc->SSC_CMR = cmr;
785
	sh->ssc->SSC_RCMR = rcmr;
786
	sh->ssc->SSC_RFMR = rfmr;
787
	sh->ssc->SSC_TCMR = tcmr;
788
	sh->ssc->SSC_TFMR = tfmr;
789
	sh->ssc->SSC_RC0R = rc0r;
790
	sh->ssc->SSC_RC1R = rc1r;
791
	
792
	sh->ssc->SSC_IDR = ~imr;
793
	sh->ssc->SSC_IER = imr;
794
	
795
	if(sr & AT91C_SSC_RXEN) 
796
		AT91F_SSC_EnableRx(sh->ssc);
797
	else
798
		AT91F_SSC_DisableRx(sh->ssc);
799
	
800
	if(sr & AT91C_SSC_TXEN) 
801
		AT91F_SSC_EnableTx(sh->ssc);
802
	else
803
		AT91F_SSC_DisableTx(sh->ssc);
804
}
805

    
806

    
807
int ssc_get_metric(ssc_metric metric, char **description, int *value)
808
{
809
	char *_name="Undefined";
810
	int _value=0;
811
	int valid=0;
812
	
813
	if(metric < sizeof(ssc_metrics)/sizeof(ssc_metrics[0])) {
814
		_name  = ssc_metrics[metric].name;
815
		_value = ssc_metrics[metric].value;
816
		valid = 1;
817
	}
818
		
819
	switch(metric) {
820
		case METRIC_FREE_RX_BUFFERS:
821
			_value = 0;
822
			int i;
823
			for(i=0; i < SSC_DMA_BUFFER_COUNT; i++)
824
				if(_rx_buffers[i].state == SSC_FREE) _value++;
825
			break;
826
		case METRIC_MANAGEMENT_ERRORS:
827
			_value = ssc_metrics[METRIC_MANAGEMENT_ERRORS_1].value +
828
				ssc_metrics[METRIC_MANAGEMENT_ERRORS_2].value +
829
				ssc_metrics[METRIC_MANAGEMENT_ERRORS_3].value;
830
			break;
831
		default:
832
			break;
833
	}
834
	
835
	if(!valid) return 0;
836
	
837
	if(description != NULL) *description = _name;
838
	if(value != NULL) *value = _value;
839
	return 1;
840
}
841

    
(45-45/59)
Add picture from clipboard (Maximum size: 48.8 MB)