eadb2ae6a99ca6ad26934e8f737a89694f882375
1 /*
2 * Copyright (c) 2013-2014, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <xdc/std.h>
33 #include <ti/xdais/ires.h>
35 #include <ti/sdo/fc/rman/rman.h>
37 #include "edmamgr.h"
38 #include "edmamgr_heap.h"
40 #ifndef ECPY_INLINE_ALL
41 #include <xdc/runtime/Diags.h>
42 #include <xdc/runtime/Log.h>
43 #include <ti/sdo/fc/ecpy/ecpy_util.h>
44 #endif
46 static IRES_ProtocolRevision _iresEDMA3ChanRevision =
47 IRES_EDMA3CHAN_PROTOCOLREVISION_2_0_0;
49 #define EDMA_MGR_MAX_NUM_CHANNELS 32
51 EdmaMgr_Channel EdmaMgr_channels[EDMA_MGR_MAX_NUM_CHANNELS];
53 extern __FAR__ int32_t *ti_sdo_fc_edmamgr_region2Instance;
54 extern __FAR__ EDMA3_GblConfigParams *ti_sdo_fc_edmamgr_edma3GblConfigParams;
55 extern __FAR__ EDMA3_InstanceInitConfig *ti_sdo_fc_edmamgr_edma3RegionConfig;
57 /*********************************************************************************
58 * FUNCTION PURPOSE: Init EdmaMgr resources
59 *********************************************************************************
60 DESCRIPTION: This function initializes RMAN resouces
62 Parameters : Inputs: proc_id : core ID
63 edma_config : pointer to EDMA3 instance init
64 configuration
65 Output: EdmaMgr_SUCCESS if initialization successful;
66 Error code otherwise
67 *********************************************************************************/
68 int32_t EdmaMgr_init(int32_t proc_id, void *edma_config)
69 {
70 IRES_Status ires_status;
71 uint32_t edmaInstanceId;
72 int32_t i;
74 if (proc_id < 0 || proc_id >= EDMA3_MAX_REGIONS) {
75 return EdmaMgr_ERROR_INVARG;
76 }
78 if (ti_sdo_fc_edmamgr_region2Instance != NULL) {
79 edmaInstanceId = ti_sdo_fc_edmamgr_region2Instance[proc_id];
81 if (ti_sdo_fc_edmamgr_edma3GblConfigParams != NULL) {
82 EDMA3_PARAMS.globalConfig =
83 (EDMA3_GblConfigParams *) &
84 ti_sdo_fc_edmamgr_edma3GblConfigParams[edmaInstanceId];
85 }
86 else if (EDMA3_PARAMS.globalConfig == NULL) {
87 return EdmaMgr_ERROR_INVCFG;
88 }
90 if (edma_config != NULL) {
91 EDMA3_InstanceInitConfig *custom_config =
92 (EDMA3_InstanceInitConfig *) edma_config;
94 EDMA3_PARAMS.regionConfig =
95 (EDMA3_InstanceInitConfig *) &
96 custom_config[EDMA3_MAX_REGIONS * edmaInstanceId + proc_id];
97 }
98 else if (ti_sdo_fc_edmamgr_edma3RegionConfig != NULL) {
99 EDMA3_PARAMS.regionConfig =
100 (EDMA3_InstanceInitConfig *) &
101 ti_sdo_fc_edmamgr_edma3RegionConfig[EDMA3_MAX_REGIONS *
102 edmaInstanceId + proc_id];
103 }
104 else if (EDMA3_PARAMS.regionConfig == NULL) {
105 return EdmaMgr_ERROR_INVCFG;
106 }
107 }
108 else if (EDMA3_PARAMS.globalConfig || EDMA3_PARAMS.regionConfig == NULL) {
109 return EdmaMgr_ERROR_INVCFG;
110 }
112 EdmaMgr_heap_create();
114 RMAN_PARAMS.allocFxn = &EdmaMgr_heap_alloc;
115 RMAN_PARAMS.freeFxn = &EdmaMgr_heap_free;
116 EDMA3_PARAMS.allocFxn = &EdmaMgr_heap_alloc;
117 EDMA3_PARAMS.freeFxn = &EdmaMgr_heap_free;
118 ECPY_CFG_PARAMS.allocFxn = &EdmaMgr_heap_alloc;
119 ECPY_CFG_PARAMS.freeFxn = &EdmaMgr_heap_free;
121 /* specify EDMA instance ID */
122 ti_sdo_fc_edma3_EDMA3_physicalId = edmaInstanceId;
124 /* RMAN init */
125 ires_status = RMAN_init();
127 if (IRES_OK != ires_status) {
128 return EdmaMgr_ERROR_RMANINIT;
129 }
131 memset(EdmaMgr_channels, 0,
132 EDMA_MGR_MAX_NUM_CHANNELS * sizeof(EdmaMgr_Channel));
133 for (i = 0; i < EDMA_MGR_MAX_NUM_CHANNELS; i++) {
134 EdmaMgr_channels[i].edmaArgs.size = sizeof(IRES_EDMA3CHAN_ProtocolArgs);
135 EdmaMgr_channels[i].edmaArgs.mode = IRES_PERSISTENT;
136 EdmaMgr_channels[i].edmaArgs.numTccs = 1;
137 EdmaMgr_channels[i].edmaArgs.paRamIndex = IRES_EDMA3CHAN_PARAM_ANY;
138 EdmaMgr_channels[i].edmaArgs.tccIndex = IRES_EDMA3CHAN_TCC_ANY;
139 EdmaMgr_channels[i].edmaArgs.qdmaChan = IRES_EDMA3CHAN_CHAN_NONE;
140 EdmaMgr_channels[i].edmaArgs.edmaChan = IRES_EDMA3CHAN_EDMACHAN_ANY;
141 EdmaMgr_channels[i].edmaArgs.contiguousAllocation = TRUE;
142 EdmaMgr_channels[i].edmaArgs.shadowPaRamsAllocation = FALSE;
143 EdmaMgr_channels[i].edmaArgs.numPaRams = 0;
144 }
145 return EdmaMgr_SUCCESS;
146 }
148 /*********************************************************************************
149 * FUNCTION PURPOSE: Allocate EdmaMgr handle
150 *********************************************************************************
151 DESCRIPTION: This function allocates an EDMA channel
153 Parameters : Inputs: max_linked_transfer : maximum number of linked
154 transfers required for the
155 channel.
157 Output: Valid EdmaMgr handle on success;
158 NULL handle if there is an error.
159 *********************************************************************************/
160 EdmaMgr_Handle EdmaMgr_alloc(int32_t max_linked_transfers)
161 {
162 IRES_ResourceDescriptor resDesc;
163 IRES_Status ires_status;
164 int32_t scratchId = -1;
165 int32_t i;
167 /* Find free channel */
168 for (i = 0; i < EDMA_MGR_MAX_NUM_CHANNELS; i++)
169 if (EdmaMgr_channels[i].edmaArgs.numPaRams == 0)
170 break;
172 if (i >= EDMA_MGR_MAX_NUM_CHANNELS)
173 return ((EdmaMgr_Handle)NULL);
175 EdmaMgr_channels[i].edmaArgs.numPaRams = max_linked_transfers;
177 /* Prepare IRES resource descriptor */
178 resDesc.resourceName = IRES_EDMA3CHAN_PROTOCOLNAME;
179 resDesc.revision = &_iresEDMA3ChanRevision;
180 resDesc.protocolArgs = (IRES_ProtocolArgs *)&(EdmaMgr_channels[i].edmaArgs);
181 resDesc.handle = (IRES_Handle)EdmaMgr_channels[i].edmaHandle;
183 /* Allocate EDMA Resources */
184 ires_status =
185 RMAN_allocateResources((Int)EdmaMgr_channels, &resDesc, 1,
186 scratchId);
187 if (ires_status != IRES_OK) {
188 EdmaMgr_channels[i].edmaArgs.numPaRams = 0;
189 return ((EdmaMgr_Handle)NULL);
190 }
191 EdmaMgr_channels[i].edmaHandle = (IRES_EDMA3CHAN_Handle) resDesc.handle;
193 /* Create ECPY handle */
194 EdmaMgr_channels[i].ecpyHandle =
195 ECPY_createHandle((IRES_EDMA3CHAN2_Handle)resDesc.handle,
196 (IALG_Handle)&EdmaMgr_channels[i]);
197 if (EdmaMgr_channels[i].ecpyHandle == NULL) {
198 RMAN_freeAllocatedResources((Int)EdmaMgr_channels, &resDesc, 1,
199 scratchId);
200 EdmaMgr_channels[i].edmaHandle = NULL;
201 EdmaMgr_channels[i].edmaArgs.numPaRams = 0;
202 return ((EdmaMgr_Handle)NULL);
203 }
204 EdmaMgr_channels[i].xferPending = FALSE;
206 /* HW assign */
207 ECPY_activate(EdmaMgr_channels[i].ecpyHandle);
208 ECPY_setEarlyCompletionMode(EdmaMgr_channels[i].ecpyHandle, FALSE);
210 return ((EdmaMgr_Handle)&EdmaMgr_channels[i]);
211 }
215 /*********************************************************************************
216 * FUNCTION PURPOSE: Allocate EdmaMgr handle
217 *********************************************************************************
218 DESCRIPTION: Get buffer requirements for a large channel.
220 Parameters : Inputs: cfg : Configuration for a large channel.
222 Output: memTab : Memory requirements.
224 Output: EdmaMgr_SUCCESS if successful;
225 Error code otherwise
226 *********************************************************************************/
227 int32_t EdmaMgr_getSizesLarge( EdmaMgr_ConfigLarge *cfg, IALG_MemRec memTab[])
228 {
229 /* Validate configuration. */
230 if ( cfg->max_num_lines <= 0 )
231 return EdmaMgr_ERROR_INVCFG;
233 memTab[0].size = cfg->max_num_lines * sizeof(uint32_t);
234 memTab[0].alignment = sizeof(uint32_t);
235 memTab[0].space = IALG_DARAM0;
236 memTab[0].attrs = IALG_PERSIST;
237 memTab[0].base = NULL;
239 return EdmaMgr_SUCCESS;
240 }
243 /*********************************************************************************
244 * FUNCTION PURPOSE: Allocate EdmaMgr handle for Large strides
245 *********************************************************************************
246 DESCRIPTION: This function allocates an EDMA channel for large transfers
247 where the pitch is larger than the HW limit of 16 bits.
249 Since these transfers excede the HW limits of a single PaRAM,
250 two channels must be chained, and "src" or "dst" addresses
251 will be stored in a look-up table.
253 The first EdmaMgr channel will read these addresses from the
254 table, and transfer them to the PaRAM of the second channel.
255 Once this transfer is complete, chaining will trigger the
256 transfer of the actual data in the second channel. Once the
257 second channel completes the transfer, chaining will trigger
258 the first channel to read the next address in the table.
259 This will continue until the entire data is transfered.
261 Parameters : Inputs: cfg : Configuration for a large channel.
263 memTab : Buffer requirements along with
264 allocated buffers for a large
265 channel.
267 Output: Valid EdmaMgr handle on success;
268 NULL handle if there is an error.
269 *********************************************************************************/
270 EdmaMgr_Handle EdmaMgr_allocLarge( EdmaMgr_ConfigLarge *cfg, IALG_MemRec memTab[])
271 {
272 EdmaMgr_Handle h1, h2;
273 EdmaMgr_Channel *chan1, *chan2;
274 uint32_t tcc1, tcc2;
276 if ( cfg->max_num_lines * sizeof(uint32_t) > memTab[0].size )
277 return ((EdmaMgr_Handle)NULL);
279 if ( memTab[0].base == NULL )
280 return ((EdmaMgr_Handle)NULL);
282 /*
283 * Allocate a basic EdmaMgr channel.
284 *
285 * This channel will be responsible for transferring addresses from the
286 * lookup table to the PaRAM of the second channel.
287 */
288 if ( (h1 = EdmaMgr_alloc(1)) == NULL )
289 return ((EdmaMgr_Handle)NULL);
291 /*
292 * Allocate a basic EdmaMgr channel.
293 *
294 * This channel will be responsible for transferring the data of interest,
295 * line by line.
296 */
297 if ( (h2 = EdmaMgr_alloc(1)) == NULL ) {
298 EdmaMgr_free(h1);
299 return ((EdmaMgr_Handle)NULL);
300 }
302 chan1 = (EdmaMgr_Channel *)h1;
303 chan2 = (EdmaMgr_Channel *)h2;
305 /* Copy over memory for the address lookup table. */
306 memcpy( &chan1->addrTable, &memTab[0], sizeof(IALG_MemRec));
308 /* Obtain each channel's TCC so that chaining can be configured, */
309 tcc1 = chan1->edmaHandle->assignedTccIndices[0];
310 tcc2 = chan2->edmaHandle->assignedTccIndices[0];
312 /* PaRAM OPT settings for first in chain. */
313 /* This TCC will load the second in the chain with the SRC address from a table in memory */
314 chan1->optChained = ECPY_PARAMOPTS_TCCBITS(tcc2) | /* Chain to the second channel's TCC */
315 ECPY_PARAMOPTS_ITCCHEN | /* Chain on intermediate transfers (after each address is loaded to the second channel). */
316 ECPY_PARAMOPTS_TCCHEN | /* Chain on final transfer (after last address is loaded). */
317 ECPY_PARAMOPTS_TCC_INTEN | /* Enable interrupt on final transfer (Sets IPR bit after final transfer). */
318 ECPY_PARAMOPTS_ABSYNC; /* Sync transfer chaining on A and B CNTs. */
320 /* PaRAM OPT settings for second in chain. */
321 /* This TCC will transfer the actual data of interest. */
322 chan2->optChained = ECPY_PARAMOPTS_TCCBITS(tcc1) | /* Chain to the first channel. */
323 ECPY_PARAMOPTS_ITCCHEN | /* Chain in intermediate transfers (to obtain next address from table). */
324 ECPY_PARAMOPTS_TCC_INTEN | /* Enable interrupt on final transfer (Sets IPR bit after final transfer). */
325 ECPY_PARAMOPTS_ABSYNC; /* Sync transfer chaining on A and B CNTs. */
327 chan1->chainedChannel = chan2;
329 return ((EdmaMgr_Handle)chan1);
330 }
332 /*********************************************************************************
333 * FUNCTION PURPOSE: Free EdmaMgr handle
334 *********************************************************************************
335 DESCRIPTION: This function frees an EDMA channel
337 Parameters : Inputs: h : EdmaMgr handle
339 Output: EdmaMgr_SUCCESS if free is successful;
340 Error code otherwise.
341 *********************************************************************************/
342 int32_t EdmaMgr_free(EdmaMgr_Handle h)
343 {
344 EdmaMgr_Channel *chan = (EdmaMgr_Channel *)h;
345 IRES_ResourceDescriptor resDesc;
346 IRES_Status ires_status;
347 int32_t scratchId = -1;
348 int32_t i, ret_val = EdmaMgr_SUCCESS;
350 /* Make sure all transfers have completed */
351 EdmaMgr_wait(h);
353 /* While loop for freeing chained channels. */
354 while ( chan != NULL ) {
355 EdmaMgr_Channel *chainedChan = chan->chainedChannel;
357 /* Verify that this is a valid handle? */
358 for (i = 0; i < EDMA_MGR_MAX_NUM_CHANNELS; i++)
359 if (chan == &EdmaMgr_channels[i])
360 break;
362 if (i >= EDMA_MGR_MAX_NUM_CHANNELS)
363 return EdmaMgr_ERROR_INVHANDLE;
365 /* Prepare IRES resource descriptor */
366 resDesc.resourceName = IRES_EDMA3CHAN_PROTOCOLNAME;
367 resDesc.revision = &_iresEDMA3ChanRevision;
368 resDesc.protocolArgs = (IRES_ProtocolArgs *)&(chan->edmaArgs);
369 resDesc.handle = (IRES_Handle)chan->edmaHandle;
371 ECPY_deleteHandle(chan->ecpyHandle);
373 ires_status =
374 RMAN_freeAllocatedResources((Int)EdmaMgr_channels, &resDesc, 1,
375 scratchId);
376 if (ires_status != IRES_OK) {
377 ret_val = EdmaMgr_ERROR_FREE;
378 }
380 chan->ecpyHandle = NULL;
381 chan->edmaHandle = NULL;
382 chan->xferPending = FALSE;
384 chan->edmaArgs.numPaRams = 0;
385 chan->chainedChannel = NULL;
387 if ( chan->addrTable.base ) {
388 EdmaMgr_heap_free(&chan->addrTable, 1);
389 chan->addrTable.base = NULL;
390 chan->addrTable.size = 0;
391 }
393 chan = chainedChan;
394 }
396 return ret_val;
397 }