Fixed problem of input task being stuck when input stream stops:
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / io / ioPhy.c
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;
62   
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   }
84   
85   /* attach I/O buffer manangement handle */
86   io_phy_inst->io_buff_handle  = params->ioBuffHandle;  
87   
88   /* set transfer frame size - interrupt generated when the frame is transfered */
89   io_phy_inst->xfer_frame_size = params->xferFrameSize;
90   
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 */
129   
130   return (io_phy_inst->xfer_frame_size);
133 /******************************************************************************
134 * API function: 
135 *    Submit transfer to underlining driver.
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   }
163   
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)
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;
283 /*======================================================================================
284  *  This function swaps HDMI input data in a given buffer
285  *====================================================================================*/
286 void hdmiDataSwap(void * buff, uint_least32_t size)
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.
301 *    - Called by audio processing task.
302 ******************************************************************************/
303 int ioPhyXferComplete(ioPhyHandle_t handle, int dataSwap)
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)
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)
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)
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 */