summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/gen5200/bestcomm/bestcomm_api.c
blob: 63916e3d09d37e5e510721fe24570b2f4af5db9a (plain) (tree)
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506





















                                                                               


















                                                                               




                                       











































































































































































































































































































































































































































































                                                                                                        
/******************************************************************************
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
* 
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
******************************************************************************/

/*!
 * \mainpage	Introduction
 *
 * \author	Motorola Semiconductor Products Sector
 * \date	2 Apr 2004
 */

/*!
 * \file	bestcomm_api.c
 *
 * Bestcomm_api.c implements most of the BestComm C API. The
 * TaskSetup() function is generated by the BestComm Task API tools
 * in capi/task_api/tasksetup_general.h as configured and included by
 * code_dma/image_rtos?/task_capi/(*).c. Other functions are defined as
 * inline in capi/bestcomm_api.h.
 */

#include "include/ppctypes.h"
#include "bestcomm_api.h"
#include "task_api/bestcomm_cntrl.h"
#include "task_api/bestcomm_api_mem.h"
#include "task_api/tasksetup_bdtable.h"

/***********************************************************************
 */
static const char* const TaskVersionString = "BestComm API v2.2 20041209";

/*
 * Hidden API data per task.
 */
 
static BDIdx BDHead[MAX_TASKS];
static BDIdx BDTail[MAX_TASKS];

/*
 * Virtual memory location of the MBAR. System registers and SRAM are
 * offset from this address.
 */
uint8 *MBarGlobal;

/*
 * Offset from MBarGlobal to get the physical memory address of the
 * MBAR. This will be zero for systems that do not use virtual memory in
 * their device driver model.
 */
sint64 MBarPhysOffsetGlobal;

/*
 * Offset to free space in SRAM after task code and buffer descriptors.
 */
uint32 SramOffsetGlobal = 0;

/*
 * This flag is false when TaskStart() has not yet been called on a
 * task newly configured by TaskSetup() or TaskStop() has been called.
 * Otherwise it is true.  It is possible that a task disabled itself
 * (transfer complete or BD ring empty) which will not show up in this
 * flag.
 *
 * It is really only useful for BD tasks that assign buffers (via
 * TaskBDAssign()) before TaskStart() or after TaskStop() are called.
 */
int TaskRunning[MAX_TASKS];

/*!
 * \brief	Get a string containing API version information.
 * \returns	Pointer to the API version string
 */
const char *TaskVersion(void)
{
	return TaskVersionString;
}

/*!
 * \brief	Initialize the API.
 * \param	MBarRef		Reference pointer to the device register memory
 *						map.
 *
 * \returns	TASK_ERR_NO_ERR on successful initialization.
 *			or TASK_ERR_API_ALREADY_INITIALIZED.
 *
 * This function is only used with physical addresses. 
 *
 * This function will also initialize API internal variables. The return
 * value TASK_ERR_API_ALREADY_INITIALIZED is intended to help determine if
 * another process has already instantiated a version of the API.
 */
int TasksInitAPI(uint8 *MBarRef)
{
	/*
	 * Copy pointer of register space to global variable.
	 * for use by other functions.
	 */
	MBarGlobal = MBarRef;
	
	/*
	 * The offset is 0 if physical and virtual are the same.
	 */
	MBarPhysOffsetGlobal = 0;
	
	/*
	 * IF API has not been initialized yet then...
	 * Make sure all BestComm interrupts are disabled and not pending.
	 * Make sure all tasks are disabled.
	 * This feature can only be put in after a way has been found to
	 * communicaticate with other processes.
	 */
	return TASK_ERR_NO_ERR;
}
 
/*!
 * \brief	Initialize the API when virtual memory is used.
 * \param	MBarRef		Reference pointer to the device register memory
 *						map.
 * \param	MBarPhys	Actual physical location of MBAR device register
 *						memory map.
 *
 * \returns	TASK_ERR_NO_ERR on successful initialization.
 *			or TASK_ERR_API_ALREADY_INITIALIZED.
 *
 * This function allows using virtual memory addresses as well as physical
 * addresses. All device registers are offset to the address supplied here,
 * so the virtual memory space should include enough space for the entire
 * register set of the device to include the SRAM space.
 *
 * This function will also initialize API internal variables. The return
 * value TASK_ERR_API_ALREADY_INITIALIZED is intended to help determine if
 * another process has already instantiated a version of the API.
 */
int TasksInitAPI_VM(uint8 *MBarRef, uint8 *MBarPhys)
{
	/*
	 * Copy pointer of register space to global variable.
	 * for use by other functions.
	 */
	MBarGlobal = MBarRef;
	MBarPhysOffsetGlobal = MBarPhys - MBarRef; 	
	
	/*
	 * If API has not been initialized yet then...
	 * Make sure all BestComm interrupts are disabled and not pending.
	 * Make sure all tasks are disabled.
	 * This feature can only be put in after a way has been found to
	 * communicaticate with other processes.
	 */
	return TASK_ERR_NO_ERR;
}
 
/*!
 * \brief	\em Deprecated
 * \param	sdma Base address of the BestComm register set
 *
 * \returns TASK_ERR_NO_ERR
 *
 * Use of this function is no longer necessary. It is retained for
 * compatibility with previous versions of the API.
 */
int TasksAttachImage(sdma_regs *sdma)
{
	return TASK_ERR_NO_ERR;
}

/*!
 * \brief	This function returns the value of the internal variable
 *			used to keep track of used space in SRAM.
 *
 * \returns The number of bytes from the beginning of SRAM to the end
 *			used space in the SRAM.
 *
 * This function will return the offset to free space in the SRAM
 * not used by the CAPI. \b Note: The returned value is based
 * on what is in TasksSetSramOffset. This function can
 * not determine what SRAM space was used by another process. There must
 * be some way external to the CAPI to keep track of SRAM space. This
 * function only returns the internal variable used to keep track of buffer
 * descriptors.
 */
uint32 TasksGetSramOffset(void)
{
	return SramOffsetGlobal;
}

/*!
 * \brief	This function stores the number of bytes from the
 *			beginning of SRAM to the end of the used space.
 *
 * \param	sram_offset	Number of bytes until the beginning of
 *						free space in the SRAM.
 *
 * This function sets the free space offset in SRAM.  It must be called
 * before setup in multi-task environments. It is the application's
 * job to determine where the free space in SRAM is. This sets the
 * base offset for the buffer descriptor variables during setup, so to
 * deallocate buffers that have already been set this function should be
 * called with a new offset.
 */
void TasksSetSramOffset(uint32 sram_offset)
{
	/*
     * Set the SramOffsetGlobal variable to be used by TaskSetup_BDTable
	 */
	SramOffsetGlobal = sram_offset;
}

/*!
 * \brief	Start an initialized task running.
 * \param	taskId	Task handle passed back from a successful TaskSetup()
 * \param	autoStartEnable Boolean for whether autostart bit is enabled.
 *							If this is set then the parameter autoStartTask
 *							defines the task to auto start.
 * \param	autoStartTask	TaskId for task to autostart. If autoStartEnable
 *							is not set then this parameter is a don't care.
 * \param	intrEnable		Boolean for interrupt enable for this task.
 * \returns	TASK_ERR_NO_ERR on success or TASK_ERR_INVALID_ARG if taskId
 *			is invalid.
 */
int TaskStart(TaskId taskId, uint32 autoStartEnable, TaskId autoStartTask,
			  uint32 intrEnable)
{
	if (intrEnable) {
		SDMA_INT_ENABLE(SDMA_INT_MASK, taskId);
	} else {
		SDMA_INT_DISABLE(SDMA_INT_MASK, taskId);
	}
	SDMA_TASK_AUTO_START(SDMA_TCR, taskId, autoStartEnable, autoStartTask)
	SDMA_TASK_ENABLE(SDMA_TCR, taskId);

	TaskRunning[taskId] = 1;
	return TASK_ERR_NO_ERR;
}

/*!
 * \brief	Stop a running task.
 * \param	taskId	Task handle passed back from a successful TaskSetup()
 * \returns	TASK_ERR_NO_ERR on success or TASK_ERR_INVALID_ARG if taskId
 *			is invalid.
 *
 * \em Note: Stopping a polling buffer descriptor task is a catastrophic
 * operation. It does not merely pause execution. Context is not
 * saved. The task's pointer into the BD ring is reset back to the
 * beginning.
 *
 * \em Note: This is not the case for the new "fall-through" BD tasks.
 * They save the BD ring pointer across stop/start boundaries. The
 * previous polling tasks are considered deprecated.
 */
int TaskStop(TaskId taskId)
{
	SDMA_INT_DISABLE(SDMA_INT_MASK, taskId);
	SDMA_TASK_DISABLE(SDMA_TCR, taskId);

	TaskRunning[taskId] = 0;
	return TASK_ERR_NO_ERR;
}

/*!
 * \brief Assign a buffer to a buffer descriptor.
 * \param taskId	Task handle passed back from a successful TaskSetup()
 * \param buffer0	A buffer to send data from or receive data into a device
 * \param buffer1	A second buffer to send data from or receive data into
 *					a device for use with double-buffer tasks.
 * \param size		Size of the buffer in bytes.
 * \param bdFlags	Buffer descriptor flags to set. Used by ethernet BD tasks.
 * \returns Handle to the buffer descriptor used by this DMA transfer.
 *			Error is indicated by a negative return value (see TaskErr_t).
 *
 * This function is used for both transmit and receive buffer descriptor
 * tasks. The buffer may be freed by the TaskBDRelease() function.
 * In the case of tasks with a buffer descriptor with two buffer pointers
 * this function uses both buffer0 and buffer1 where buffer0 is a source
 * and buffer1 is a destination. When the buffer descriptor is a single
 * pointer type, the buffer0 is the only pointer used and buffer1 is ignored.
 *
 * Using this function on non-buffer descriptor tasks will produce
 * unpredictable results.
 */
BDIdx TaskBDAssign(TaskId taskId, void *buffer0, void *buffer1, int size, uint32 bdFlags)
{
	BDIdx		*bdHead;
	TaskBD_t	*bd;
	BDIdx		r = TASK_ERR_NO_ERR;

	if (TaskBDIdxTable[taskId].currBDInUse == TaskBDIdxTable[taskId].numBD) {
		/*
		 * The buffer ring is full.
		 */
		r = TASK_ERR_BD_RING_FULL;

	} else if (   (TaskBDIdxTable[taskId].apiConfig & API_CONFIG_BD_FLAG)
			   && ((uint32)size & (uint32)(~SDMA_DRD_MASK_LENGTH))) {
		r = TASK_ERR_SIZE_TOO_LARGE;

	} else if (   !(TaskBDIdxTable[taskId].apiConfig & API_CONFIG_BD_FLAG)
			   && ((uint32)size & (uint32)(0xffffffff<<SDMA_BD_BIT_READY))) {
		r = TASK_ERR_SIZE_TOO_LARGE;

	} else {
		bdHead = &BDHead[taskId];

		/*
		 * Increase Buffer Descriptor in-use variable.
		 */
		++TaskBDIdxTable[taskId].currBDInUse;

		/*
		 * Get a generic TaskBD_t pointer to the BD to be assigned.
		 * Assign the buffer pointers.
		 */
		bd = TaskBDIdxTable[taskId].BDTablePtr;
		if (TaskBDIdxTable[taskId].numPtr == 1) {
			bd = (TaskBD_t *)&(((TaskBD1_t *)bd)[*bdHead]);

			((TaskBD1_t *)bd)->DataPtr[0] = (uint32)buffer0;
		} else {
			bd = (TaskBD_t *)&(((TaskBD2_t *)bd)[*bdHead]);

			((TaskBD2_t *)bd)->DataPtr[0] = (uint32)buffer0;
			((TaskBD2_t *)bd)->DataPtr[1] = (uint32)buffer1;
		}


		if (bd->Status & SDMA_BD_MASK_READY) {
			/*
			 * This BD is in use.
			 */
			r = TASK_ERR_BD_BUSY;

		} else {

			/*
			 * Set status bits and length. As soon as Status is written, the
			 * BestComm may perform the transfer.
			 */
			if (TaskBDIdxTable[taskId].apiConfig & API_CONFIG_BD_FLAG) {
				bd->Status = ( ((uint32)SDMA_DRD_MASK_FLAGS  & bdFlags)
							 | ((uint32)SDMA_DRD_MASK_LENGTH & (uint32)size)
							 | ((uint32)SDMA_BD_MASK_READY));
			} else {
				bd->Status = ( ((uint32)SDMA_BD_MASK_SIGN    & (uint32)size)
							 | ((uint32)SDMA_BD_MASK_READY));
			}

			/*
			 * Return the current BD index and increment.
			 */
			r = *bdHead;
			*bdHead = (BDIdx)((*bdHead + 1) % (BDIdx)TaskBDIdxTable[taskId].numBD);
		}
	}

	/*
	 * Reenable a fall-through BD tasks that might have exited.
	 */
	if (TaskRunning[taskId]) {
		SDMA_TASK_ENABLE(SDMA_TCR, taskId);
	}
	return r;
}

/*!
 * \brief Release last buffer in the buffer descriptor ring.
 * \param taskId	Task handle passed back from a successful TaskSetup()
 *
 * \returns Buffer descriptor index of next buffer index that will be released
 *			by another call of this function.
 *			TASK_ERR_BD_RING_EMPTY is returned if the ring is already empty.
 *
 * This function allows the system to reallocate the memory used by
 * the buffer. It also cleans up the structure in the BD ring by
 * removing the tail buffer in the ring. The buffer descriptor tasks
 * are designed around this. Non-BD tasks do not use this function.
 *
 * Using this function on non-buffer descriptor tasks will produce
 * unpredictable results.
 */
BDIdx TaskBDRelease(TaskId taskId)
{
	BDIdx		*bdTail;
	TaskBD_t	*bd;

	bdTail = &BDTail[taskId];

	if (TaskBDIdxTable[taskId].currBDInUse == 0) {
		/*
		 * Buffer Descriptor ring is empty, Can't Release!
		 */
		 return TASK_ERR_BD_RING_EMPTY;
	}

	/*
	 * Get a generic TaskBD_t pointer to the next BD to be released.
	 */
	bd = TaskGetBD(taskId, *bdTail);

	/*
	 * Verify the ready bit is clear.
	 */
	if (bd->Status & SDMA_BD_MASK_READY) {
		return TASK_ERR_BD_BUSY;
	}

	/*
	 * Increment the tail pointer around the ring, decrement in-use.
	 */
	*bdTail = (BDIdx)((*bdTail + 1) % (BDIdx)TaskBDIdxTable[taskId].numBD);
	--TaskBDIdxTable[taskId].currBDInUse;

	return *bdTail;
}


/*!
 * \brief Release all buffers.
 * \param taskId	Task handle passed back from a successful TaskSetup()
 *
 * \returns Buffer descriptor index of next buffer that will be
 *			assigned by TaskBDAssign() which will also be the first
 *			released by the next call to TaskBDRelease() or
 *			TASK_ERR_TASK_RUNNING if the task has not been stopped.
 *
 * This function is similar to TaskBDRelease() except that it releases
 * all assigned buffers including those not yet processed by the BestComm
 * task; i.e. SDMA_BD_MASK_READY is set.
 * Non-BD tasks do not use this
 * function.
 *
 * The task should not be running. Call TaskStop() first.
 *
 * \em Note: Partially transmitted buffers are up to the user to handle.
 *
 * Using this function on non-buffer descriptor tasks will produce
 * unpredictable results.
 */
BDIdx TaskBDReset(TaskId taskId)
{
	BDIdx		i;
	TaskBD_t	*bd, *bdTab;

	if (TaskRunning[taskId]) {
		return TASK_ERR_TASK_RUNNING;
	}

	bdTab = TaskBDIdxTable[taskId].BDTablePtr;

	for (i = (BDIdx)TaskBDIdxTable[taskId].numBD - 1; i >= 0; --i) {

		if (TaskBDIdxTable[taskId].numPtr == 1) {
			bd = (TaskBD_t *)&(((TaskBD1_t *)bdTab)[i]);
		} else {
			bd = (TaskBD_t *)&(((TaskBD2_t *)bdTab)[i]);
		}

		bd->Status = 0x0;
	}

	TaskBDIdxTable[taskId].currBDInUse = 0;
	*TaskBDIdxTable[taskId].BDStartPtr =
		(volatile uint32)((volatile uint32)TaskBDIdxTable[taskId].BDTablePtr
						+ MBarPhysOffsetGlobal);
	return BDHead[taskId] = BDTail[taskId] = 0;
}


/*!
 * \brief	Return BestComm debug information.
 * \param	taskId	Task handle passed back from a successful TaskSetup()
 * \param	paramSet	TBD
 * \returns	TBD
 *
 * The implementation of this function is yet to be determined.
 */
int TaskDebug(TaskId taskId, TaskDebugParamSet_t *paramSet)
{
	if ((taskId < 0) || (taskId >= MAX_TASKS)) {
		return TASK_ERR_INVALID_ARG;
	}
	if (paramSet == NULL) {
		return TASK_ERR_INVALID_ARG;
	}

	return TASK_ERR_NO_ERR;
}