2 #include "ioPhy.h"
3 #include "ioPhy_loc.h"
4 #include "libarch.h"
5 #include "mcasp_drv.h"
7 #include <stdint.h>
8 #include <xdc/runtime/System.h> // for System_printf
9 #include <ti/sysbios/hal/Cache.h>
11 #define NUM_MCASP_PRIME_PACKETS 3 // should be provided by McASP driver
13 /******************************************************************************
14 * Implementation of I/O Physical Layer Component
15 ******************************************************************************/
17 #define IOPHY_NUM_MEM_ALLOCS 1
18 #define IOPHY_INST_ALIGN 3
20 //C:\ti\edma3_lld_2_12_01_24\packages\ti\sdo\edma3\drv\sample\src\platforms\sample_tci66ak2g02_cfg.c
21 extern signed char* getGlobalAddr(signed char* addr); // to be replaced by lib_getGlobalAddr
23 /*******************************************************************************
24 * API function: ioPhyNumAlloc
25 * Returns the maximum number of memory allocation requests that ioPhyAlloc()
26 * requires.
27 *******************************************************************************/
28 int ioPhyNumAlloc(void)
29 {
30 return (IOPHY_NUM_MEM_ALLOCS);
31 }
33 /*******************************************************************************
34 * API function: ioPhyAlloc
35 * Returns a table of memory records that describe the size, alignment, type
36 * and memory space of all buffers required by I/O PHY component.
37 *******************************************************************************/
38 int ioPhyAlloc(lib_mem_rec_t *mem_tbl)
39 {
40 mem_tbl[0].size = sizeof(ioPhyInst_t);
41 mem_tbl[0].alignment = IOPHY_INST_ALIGN;
42 mem_tbl[0].type = LIB_PMEM_SLOW;
43 mem_tbl[0].base = NULL;
45 return (IOPHY_NOERR);
46 }
48 /******************************************************************************
49 * API function:
50 * I/O physical layer creation.
51 ******************************************************************************/
52 int ioPhyCreate(ioPhyHandle_t *handle, const lib_mem_rec_t *mem_tbl)
53 {
54 ioPhyInst_t *io_phy_inst;
56 if( (mem_tbl[0].size < sizeof(ioPhyInst_t))
57 ||libChkAlign(mem_tbl[0].base, IOPHY_INST_ALIGN) ) {
58 return (IOPHY_ERR_MEMORY);
59 }
61 io_phy_inst = (ioPhyInst_t *)mem_tbl[0].base;
63 /* return I/O PHY instance */
64 *handle = (ioPhyHandle_t *)io_phy_inst;
66 return (IOPHY_NOERR);
67 }
69 /******************************************************************************
70 * API function:
71 * I/O physical layer initialization.
72 ******************************************************************************/
73 int ioPhyInit(ioPhyHandle_t handle, const ioPhyParams_t *params)
74 {
75 ioPhyInst_t *io_phy_inst;
76 Mcasp_IOcmd_e mcasp_cmd;
77 int i;
79 io_phy_inst = (ioPhyInst_t *)handle;
81 if(params == NULL) {
82 return (IOPHY_ERR_BAD_PARAMS);
83 }
85 /* attach I/O buffer manangement handle */
86 io_phy_inst->io_buff_handle = params->ioBuffHandle;
88 /* set transfer frame size - interrupt generated when the frame is transfered */
89 io_phy_inst->xfer_frame_size = params->xferFrameSize;
91 /* attach McASP driver channel handle */
92 io_phy_inst->mcasp_chan_handle = params->mcaspChanHandle;
94 /* set the operation that I/O PHY will perform to I/O buffer - read or write */
95 io_phy_inst->ioBuffOp = params->ioBuffOp;
97 /* attach ioBuff functions based on buffer operation */
98 if(params->ioBuffOp == IOPHY_IOBUFFOP_READ) {
99 io_phy_inst->ioBuffMarkComplete = ioBuffReadComplete;
100 io_phy_inst->ioBuffGetPtrs = ioBuffGetReadPtrs;
101 mcasp_cmd = MCASP_WRITE;
102 } else {
103 io_phy_inst->ioBuffMarkComplete = ioBuffWriteComplete;
104 io_phy_inst->ioBuffGetPtrs = ioBuffGetWritePtrs;
105 mcasp_cmd = MCASP_READ;
106 }
107 for(i=0; i<IOPHY_NUM_XFER_RECORD; i++)
108 {
109 io_phy_inst->xfered_packets[i].cmd = mcasp_cmd;
110 }
111 io_phy_inst->mcasp_cmd = mcasp_cmd;
113 /* initialize status variables */
114 io_phy_inst->sync_cntr = 0; /* to keep track xfer submit and complete */
115 io_phy_inst->submit_ind = 0; /* index to submited McASP packets */
116 io_phy_inst->complete_ind = 0; /* index to completed McASP packets */
118 return (IOPHY_NOERR);
119 } /* ioPhyInit */
121 /******************************************************************************
122 * I/O PHY internal function:
123 * Calculate transfer size in bytes based on encoding frame size passed
124 * through ioPhyControl.
125 ******************************************************************************/
126 static size_t ioPhy_calc_xfer_size(ioPhyInst_t *io_phy_inst)
127 {
128 /* calc. xfer size based on io_phy_inst->frame_size */
130 return (io_phy_inst->xfer_frame_size);
131 }
133 /******************************************************************************
134 * API function:
135 * Submit transfer to underlining driver.
136 *
137 * - Called by audio processing task.
138 ******************************************************************************/
139 int ioPhyXferSubmit(ioPhyHandle_t handle)
140 {
141 int submit_ind, err_code, ret_value;
142 void *buff1, *buff2;
143 size_t size1, size2, xfer_size;
144 ioPhyInst_t *io_phy_inst = (ioPhyInst_t *)handle;
146 /* Figure out the transfer size in bytes */
147 xfer_size = ioPhy_calc_xfer_size(io_phy_inst); // internal function
149 ret_value = IOPHY_NOERR;
151 /* Get one or two buffers from I/O buffer management for write */
152 err_code = io_phy_inst->ioBuffGetPtrs(io_phy_inst->io_buff_handle, xfer_size,
153 &buff1, &size1, &buff2, &size2);
155 /* Don't return from here even if ioBuff overflows or underflows, since McASP
156 needs to be running and generating interrupts all the time. */
157 if(err_code == IOBUFF_ERR_UNDERFLOW) {
158 ret_value = IOPHY_ERR_BUFF_UNDERFLOW;
159 }
160 if(err_code == IOBUFF_ERR_OVERFLOW) {
161 ret_value = IOPHY_ERR_BUFF_OVERFLOW;
162 }
164 /* ioBuff needs to provide buffer to read/write even if it underflows/overflows */
165 if(buff1 == NULL) {
166 return (IOPHY_ERR_BUFF_BADPTRS);
167 }
169 /* Submit 1 or 2 transfers depending on whether I/O buffer wraps around */
170 submit_ind = io_phy_inst->submit_ind;
172 /* Compose McASP packet and save in the instance - McASP driver requires
173 the packet to be in permanent memory so that it can provide the packet
174 to the callback function. */
175 // io_phy_inst->xfered_packets[submit_ind].cmd = 0;
176 io_phy_inst->xfered_packets[submit_ind].addr = (void*)(getGlobalAddr(buff1));
177 io_phy_inst->xfered_packets[submit_ind].size = size1;
178 io_phy_inst->xfered_packets[submit_ind].status = 0;
179 io_phy_inst->xfer_rec[submit_ind].base = buff1;
180 io_phy_inst->xfer_rec[submit_ind].size = size1;
182 if(buff2 == NULL) {
183 /* There is no wrap around in I/O buffer - submit one transfer */
184 /* indicate that this is the final transfer of a frame */
185 io_phy_inst->xfered_packets[submit_ind].arg = IOPHY_XFER_FINAL;
186 io_phy_inst->xfer_rec[submit_ind].packet_status = IOPHY_XFER_FINAL;
187 } else {
188 /* There is wrap around in I/O buffer - submit two tranfers */
189 /* indicate that this is the intermediate transfer of a frame */
190 io_phy_inst->xfered_packets[submit_ind].arg = IOPHY_XFER_INTER;
191 io_phy_inst->xfer_rec[submit_ind].packet_status = IOPHY_XFER_INTER;
192 }
194 /* make a transfer request */
195 if((err_code = mcaspSubmitChan(io_phy_inst->mcasp_chan_handle,
196 &io_phy_inst->xfered_packets[submit_ind])) != 1) {
197 //System_printf("mcaspSubmitChan failed with handle 0x%x and error code %d!\n",
198 // (unsigned int)io_phy_inst->mcasp_chan_handle, err_code);
199 return(IOPHY_ERR_MCASP_FAIL);
200 }
202 /* update submit index */
203 submit_ind++;
204 if(submit_ind == IOPHY_NUM_XFER_RECORD) {
205 submit_ind = 0;
206 }
207 io_phy_inst->submit_ind = submit_ind;
209 /* make another transfer request if ioBuff wraps around */
210 if(buff2 != NULL) {
211 /* Compose McASP packets and save in the instance */
212 //io_phy_inst->xfered_packets[submit_ind].cmd = 0;
213 io_phy_inst->xfered_packets[submit_ind].addr = (void*)(getGlobalAddr(buff2));
214 io_phy_inst->xfered_packets[submit_ind].size = size2;
215 io_phy_inst->xfered_packets[submit_ind].status = 0;
216 /* indicate that this is the final transfer of a frame */
217 io_phy_inst->xfered_packets[submit_ind].arg = IOPHY_XFER_FINAL;
219 io_phy_inst->xfer_rec[submit_ind].base = buff2;
220 io_phy_inst->xfer_rec[submit_ind].size = size2;
221 io_phy_inst->xfer_rec[submit_ind].packet_status = IOPHY_XFER_FINAL;
223 if((err_code = mcaspSubmitChan(io_phy_inst->mcasp_chan_handle,
224 &io_phy_inst->xfered_packets[submit_ind])) != 1) {
225 //System_printf("mcaspSubmitChan failed with handle 0x%x and error code %d!\n",
226 // (unsigned int)io_phy_inst->mcasp_chan_handle, err_code);
227 return(IOPHY_ERR_MCASP_FAIL);
228 }
230 submit_ind++;
231 if(submit_ind == IOPHY_NUM_XFER_RECORD) {
232 submit_ind = 0;
233 }
234 io_phy_inst->submit_ind = submit_ind;
235 }
237 return (ret_value);
238 } /* ioPhyXferSubmit() */
241 void swapData(void *buff, uint_least32_t size)
242 {
243 int i;
244 int_least16_t L0, L1, L2, L3, R0, R1, R2, R3 = 0;
245 int_least16_t *p1, *p2;
247 int_least16_t *dataPtr = (int_least16_t *)buff;
248 /*
249 for (i=0; i<size/2; i++)
250 {
251 if(dataPtr[i] == (int_least16_t)0xF872) {
252 dataPtr[i] = 0x278F;
253 }
254 }
255 */
256 for (i=0; i<size/2; i+=8)
257 {
258 p1 = &dataPtr[i];
259 p2 = p1;
261 L0 = *p1++;
262 L1 = *p1++;
263 L2 = *p1++;
264 L3 = *p1++;
265 R0 = *p1++;
266 R1 = *p1++;
267 R2 = *p1++;
268 R3 = *p1++;
270 *p2++ = L0;
271 *p2++ = R0;
272 *p2++ = L1;
273 *p2++ = R1;
274 *p2++ = L2;
275 *p2++ = R2;
276 *p2++ = L3;
277 *p2++ = R3;
278 }
280 return;
281 }
283 /*======================================================================================
284 * This function swaps HDMI input data in a given buffer
285 *====================================================================================*/
286 void hdmiDataSwap(void * buff, uint_least32_t size)
287 {
288 Cache_inv(buff, size, Cache_Type_ALL, 0);
289 Cache_wait();
291 swapData(buff, size);
293 Cache_wb (buff, size, Cache_Type_ALL, 0);
294 Cache_wait();
295 } /* ioDataSwapBuffer */
297 /******************************************************************************
298 * API function:
299 * Marks I/O buffer read/write complete.
300 *
301 * - Called by audio processing task.
302 ******************************************************************************/
303 int ioPhyXferComplete(ioPhyHandle_t handle, int dataSwap)
304 {
305 int complete_ind;
306 void *buff;
307 size_t size;
309 ioPhyInst_t *io_phy_inst = (ioPhyInst_t *)handle;
311 /* Based on index to completed packets, find the base address and size of the
312 just completed McASP packet and pass to ioBuff to mark read/write complete. */
313 complete_ind = io_phy_inst->complete_ind;
314 buff = io_phy_inst->xfer_rec[complete_ind].base;
315 size = io_phy_inst->xfer_rec[complete_ind].size;
317 if(dataSwap) {
318 hdmiDataSwap(buff, size);
319 }
321 io_phy_inst->ioBuffMarkComplete(io_phy_inst->io_buff_handle, buff, size);
323 /* Check if this is a single McASP transfer or batch transfer */
324 if(io_phy_inst->xfer_rec[complete_ind].packet_status == IOPHY_XFER_INTER) {
325 /* This is a batch transfer, so also mark next packet as complete. */
326 complete_ind++;
327 if(complete_ind == IOPHY_NUM_XFER_RECORD) {
328 complete_ind = 0;
329 }
331 if(io_phy_inst->xfer_rec[complete_ind].packet_status == IOPHY_XFER_FINAL) {
332 buff = io_phy_inst->xfer_rec[complete_ind].base;
333 size = io_phy_inst->xfer_rec[complete_ind].size;
335 if(dataSwap) {
336 hdmiDataSwap(buff, size);
337 }
339 io_phy_inst->ioBuffMarkComplete(io_phy_inst->io_buff_handle, buff, size);
340 } else {
341 // error!
342 }
343 }
345 /* increment index to point to next completed packet */
346 io_phy_inst->complete_ind = complete_ind+1;
347 if(io_phy_inst->complete_ind == IOPHY_NUM_XFER_RECORD) {
348 io_phy_inst->complete_ind = 0;
349 }
351 return (IOPHY_NOERR);
352 } /* ioPhyXferComplete() */
355 // TODO: add error check and recovery mechanism
356 int ioPhyCheckXferStatus(ioPhyHandle_t handle, MCASP_Packet *mcasp_packet)
357 {
358 int complete_ind, temp_ind;
359 ioPhyInst_t *io_phy_inst = (ioPhyInst_t *)handle;
361 // complete_ind points to the packet to be marked as complete
362 complete_ind = io_phy_inst->complete_ind;
363 temp_ind = complete_ind + 1;
364 if(temp_ind == IOPHY_NUM_XFER_RECORD) {
365 temp_ind = 0;
366 }
368 // check if next completed packet is part of two-packet transfer or not:
369 // - if two-packet transfer, it points to the first packet
370 // - if one-packet transfer, it points to the only packet
371 if(io_phy_inst->xfer_rec[complete_ind].packet_status == IOPHY_XFER_INTER) {
372 // this is a two-packet transfer and this function may be called after either the
373 // first or the second packet has been transfered.
374 if( (mcasp_packet->arg == IOPHY_XFER_INTER) // first packet
375 && (mcasp_packet->addr == io_phy_inst->xfer_rec[complete_ind].base) ) {
376 // this is the first packet
377 return (IOPHY_XFER_INTER);
378 }
379 else if( (mcasp_packet->arg == IOPHY_XFER_FINAL) // second packet
380 && (mcasp_packet->addr == io_phy_inst->xfer_rec[temp_ind].base) ) {
381 // this is the second packet
382 return (IOPHY_XFER_FINAL);
383 }
384 else {
385 return (IOPHY_XFER_ERROR);
386 }
387 }
388 else {
389 // this is a one-packet transfer
390 if( (mcasp_packet->arg == IOPHY_XFER_FINAL)
391 &&(mcasp_packet->addr == io_phy_inst->xfer_rec[complete_ind].base) ) {
392 return (IOPHY_XFER_FINAL);
393 }
394 else {
395 return (IOPHY_XFER_ERROR);
396 }
397 }
399 #if 0
400 if(mcasp_packet->addr != io_phy_inst->xfer_rec[io_phy_inst->complete_ind].base) {
401 return (IOPHY_XFER_ERROR);
402 }
404 if(mcasp_packet->arg == IOPHY_XFER_FINAL) {
405 return (IOPHY_XFER_FINAL);
406 }
407 else if (mcasp_packet->arg == IOPHY_XFER_INTER) {
408 return (IOPHY_XFER_INTER);
409 }
410 else {
411 return (IOPHY_XFER_ERROR);
412 }
413 #endif
415 } /* ioPhyCheckXferStatus */
418 /******************************************************************************
419 * API function: run-time control of IO Configuration component
420 ******************************************************************************/
421 int ioPhyControl(ioPhyHandle_t handle, ioPhyCtl_t *ctl)
422 {
423 ioPhyInst_t *io_phy_inst = (ioPhyInst_t *)handle;
425 switch(ctl->code) {
426 case IOPHY_CTL_FRAME_SIZE:
427 /* pass data frame size */
428 io_phy_inst->xfer_frame_size = ctl->params.xferFrameSize;
429 break;
431 case IOPHY_CTL_INPUT_CHANGE:
432 //ioPhyInit(handle, ctl->ioPhyRxParams);
433 break;
435 default:
436 break;
437 }
439 return (IOPHY_NOERR);
440 } /* ioPhyControl */
442 // change this API to something like ioPhyXferReSubmit(ioPhyHandle_t handle, int numXfer)
443 int ioPhyXferErrRecover(ioPhyHandle_t handle)
444 {
445 int submit_ind, i;
446 ioPhyInst_t *io_phy_inst = (ioPhyInst_t *)handle;
448 /* resend the latest #NUM_MCASP_PRIME_PACKETS packets */
449 submit_ind = io_phy_inst->submit_ind - NUM_MCASP_PRIME_PACKETS;
450 //submit_ind = io_phy_inst->submit_ind - (NUM_MCASP_PRIME_PACKETS-1);
451 if(submit_ind < 0) {
452 submit_ind += IOPHY_NUM_XFER_RECORD;
453 }
455 for(i=0; i<NUM_MCASP_PRIME_PACKETS; i++)
456 {
457 if((mcaspSubmitChan(io_phy_inst->mcasp_chan_handle,
458 &io_phy_inst->xfered_packets[submit_ind])) != 1) {
459 return(IOPHY_ERR_MCASP_FAIL);
460 }
462 submit_ind++;
463 if(submit_ind == IOPHY_NUM_XFER_RECORD) {
464 submit_ind = 0;
465 }
466 }
468 io_phy_inst->submit_ind = submit_ind;
470 return (IOPHY_NOERR);
471 } /* ioPhyXferErrRecover */