]> git.sur5r.net Git - freertos/blob
e1551a7a5deed12a463c8837769b40440bf093f9
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2015 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 * @file xiicps_slave.c
35 *
36 * Handles slave transfers
37 *
38 * <pre> MODIFICATION HISTORY:
39 *
40 * Ver   Who Date     Changes
41 * ----- --  -------- ---------------------------------------------
42 * 1.00a jz  01/30/10 First release
43 * 1.04a kpc 08/30/13 Avoid buffer overwrite in SlaveRecvData function
44 * 3.00  sk      01/31/15 Modified the code according to MISRAC 2012 Compliant.
45 *
46 * </pre>
47 *
48 ******************************************************************************/
49
50 /***************************** Include Files *********************************/
51 #include "xiicps.h"
52
53 /************************** Constant Definitions *****************************/
54
55 /**************************** Type Definitions *******************************/
56
57 /***************** Macros (Inline Functions) Definitions *********************/
58
59 /************************** Function Prototypes ******************************/
60 extern s32 TransmitFifoFill(XIicPs *InstancePtr);
61
62 static s32 SlaveRecvData(XIicPs *InstancePtr);
63
64 /************************* Variable Definitions *****************************/
65
66 /*****************************************************************************/
67 /**
68 * This function sets up the device to be a slave.
69 *
70 * @param        InstancePtr is a pointer to the XIicPs instance.
71 * @param        SlaveAddr is the address of the slave we are receiving from.
72 *
73 * @return       None.
74 *
75 * @note
76 *       Interrupt is always enabled no matter the tranfer is interrupt-
77 *       driven or polled mode. Whether device will be interrupted or not
78 *       depends on whether the device is connected to an interrupt
79 *       controller and interrupt for the device is enabled.
80 *
81 ****************************************************************************/
82 void XIicPs_SetupSlave(XIicPs *InstancePtr, u16 SlaveAddr)
83 {
84         u32 ControlReg;
85         u32 BaseAddr;
86
87         Xil_AssertVoid(InstancePtr != NULL);
88         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
89         Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr);
90
91         BaseAddr = InstancePtr->Config.BaseAddress;
92
93         ControlReg = XIicPs_In32(BaseAddr + XIICPS_CR_OFFSET);
94
95         /*
96          * Set up master, AckEn, nea and also clear fifo.
97          */
98         ControlReg |= (u32)XIICPS_CR_ACKEN_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK;
99         ControlReg |= (u32)XIICPS_CR_NEA_MASK;
100         ControlReg &= (u32)(~XIICPS_CR_MS_MASK);
101
102         XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
103                           ControlReg);
104
105         XIicPs_DisableAllInterrupts(BaseAddr);
106
107         XIicPs_WriteReg(InstancePtr->Config.BaseAddress,
108                           XIICPS_ADDR_OFFSET, (u32)SlaveAddr);
109
110         return;
111 }
112
113 /*****************************************************************************/
114 /**
115 * This function setup a slave interrupt-driven send. It set the repeated
116 * start for the device is the tranfer size is larger than FIFO depth.
117 * Data processing for the send is initiated by the interrupt handler.
118 *
119 * @param        InstancePtr is a pointer to the XIicPs instance.
120 * @param        MsgPtr is the pointer to the send buffer.
121 * @param        ByteCount is the number of bytes to be sent.
122 *
123 * @return       None.
124 *
125 * @note         This send routine is for interrupt-driven transfer only.
126 *
127 ****************************************************************************/
128 void XIicPs_SlaveSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
129 {
130         u32 BaseAddr;
131
132         /*
133          * Assert validates the input arguments
134          */
135         Xil_AssertVoid(InstancePtr != NULL);
136         Xil_AssertVoid(MsgPtr != NULL);
137         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
138
139
140         BaseAddr = InstancePtr->Config.BaseAddress;
141         InstancePtr->SendBufferPtr = MsgPtr;
142         InstancePtr->SendByteCount = ByteCount;
143         InstancePtr->RecvBufferPtr = NULL;
144
145         XIicPs_EnableInterrupts(BaseAddr,
146                         (u32)XIICPS_IXR_DATA_MASK | (u32)XIICPS_IXR_COMP_MASK |
147                         (u32)XIICPS_IXR_TO_MASK | (u32)XIICPS_IXR_NACK_MASK |
148                         (u32)XIICPS_IXR_TX_OVR_MASK);
149 }
150
151 /*****************************************************************************/
152 /**
153 * This function setup a slave interrupt-driven receive.
154 * Data processing for the receive is handled by the interrupt handler.
155 *
156 * @param        InstancePtr is a pointer to the XIicPs instance.
157 * @param        MsgPtr is the pointer to the receive buffer.
158 * @param        ByteCount is the number of bytes to be received.
159 *
160 * @return       None.
161 *
162 * @note         This routine is for interrupt-driven transfer only.
163 *
164 ****************************************************************************/
165 void XIicPs_SlaveRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
166 {
167         /*
168          * Assert validates the input arguments.
169          */
170         Xil_AssertVoid(InstancePtr != NULL);
171         Xil_AssertVoid(MsgPtr != NULL);
172         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
173
174
175         InstancePtr->RecvBufferPtr = MsgPtr;
176         InstancePtr->RecvByteCount = ByteCount;
177         InstancePtr->SendBufferPtr = NULL;
178
179         XIicPs_EnableInterrupts(InstancePtr->Config.BaseAddress,
180                 (u32)XIICPS_IXR_DATA_MASK | (u32)XIICPS_IXR_COMP_MASK |
181                 (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_TO_MASK |
182                 (u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_RX_UNF_MASK);
183
184 }
185
186 /*****************************************************************************/
187 /**
188 * This function sends  a buffer in polled mode as a slave.
189 *
190 * @param        InstancePtr is a pointer to the XIicPs instance.
191 * @param        MsgPtr is the pointer to the send buffer.
192 * @param        ByteCount is the number of bytes to be sent.
193 *
194 * @return
195 *               - XST_SUCCESS if everything went well.
196 *               - XST_FAILURE if master sends us data or master terminates the
197 *               transfer before all data has sent out.
198 *
199 * @note         This send routine is for polled mode transfer only.
200 *
201 ****************************************************************************/
202 s32 XIicPs_SlaveSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
203 {
204         u32 IntrStatusReg;
205         u32 StatusReg;
206         u32 BaseAddr;
207         s32 Tmp;
208         s32 BytesToSend;
209         s32 Error = 0;
210         s32 Status = (s32)XST_SUCCESS;
211         u32 Value;
212
213         /*
214          * Assert validates the input arguments.
215          */
216         Xil_AssertNonvoid(InstancePtr != NULL);
217         Xil_AssertNonvoid(MsgPtr != NULL);
218         Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
219
220         BaseAddr = InstancePtr->Config.BaseAddress;
221         InstancePtr->SendBufferPtr = MsgPtr;
222         InstancePtr->SendByteCount = ByteCount;
223
224         /*
225          * Use RXRW bit in status register to wait master to start a read.
226          */
227         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
228         while (((StatusReg & XIICPS_SR_RXRW_MASK) == 0U) &&
229                                 ((!Error) != 0)) {
230
231                 /*
232                  * If master tries to send us data, it is an error.
233                  */
234                 if ((StatusReg & XIICPS_SR_RXDV_MASK) != 0x0U) {
235                         Error = 1;
236                 }
237
238                 StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
239         }
240
241         if (Error != 0) {
242                 Status = (s32)XST_FAILURE;
243         } else {
244
245                 /*
246                  * Clear the interrupt status register.
247                  */
248                 IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
249                 XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
250
251                 /*
252                  * Send data as long as there is more data to send and
253                  * there are no errors.
254                  */
255                 Value = (InstancePtr->SendByteCount > (s32)0) &&
256                                                 ((!Error) != 0);
257                 while (Value != (u32)0x00U) {
258
259                         /*
260                          * Find out how many can be sent.
261                          */
262                         BytesToSend = InstancePtr->SendByteCount;
263                         if (BytesToSend > (s32)(XIICPS_FIFO_DEPTH)) {
264                                 BytesToSend = (s32)(XIICPS_FIFO_DEPTH);
265                         }
266
267                         for(Tmp = 0; Tmp < BytesToSend; Tmp ++) {
268                                 XIicPs_SendByte(InstancePtr);
269                         }
270
271                         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
272
273                         /*
274                          * Wait for master to read the data out of fifo.
275                          */
276                         while (((StatusReg & XIICPS_SR_TXDV_MASK) != (u32)0x00U) &&
277                                                         ((!Error) != 0)) {
278
279                                 /*
280                                  * If master terminates the transfer before all data is
281                                  * sent, it is an error.
282                                  */
283                                 IntrStatusReg = XIicPs_ReadReg(BaseAddr,
284                                 XIICPS_ISR_OFFSET);
285                                 if ((IntrStatusReg & XIICPS_IXR_NACK_MASK) != 0x0U) {
286                                         Error = 1;
287                                 }
288
289                                 /* Clear ISR.
290                                  */
291                                 XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET,
292                                                         IntrStatusReg);
293
294                                 StatusReg = XIicPs_ReadReg(BaseAddr,
295                                                 XIICPS_SR_OFFSET);
296                         }
297                         Value = (InstancePtr->SendByteCount > (s32)0U) &&
298                                                         ((!Error) != 0);
299                 }
300         }
301         if (Error != 0) {
302         Status = (s32)XST_FAILURE;
303         }
304
305         return Status;
306 }
307 /*****************************************************************************/
308 /**
309 * This function receives a buffer in polled mode as a slave.
310 *
311 * @param        InstancePtr is a pointer to the XIicPs instance.
312 * @param        MsgPtr is the pointer to the receive buffer.
313 * @param        ByteCount is the number of bytes to be received.
314 *
315 * @return
316 *               - XST_SUCCESS if everything went well.
317 *               - XST_FAILURE if timed out.
318 *
319 * @note         This receive routine is for polled mode transfer only.
320 *
321 ****************************************************************************/
322 s32 XIicPs_SlaveRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount)
323 {
324         u32 IntrStatusReg;
325         u32 StatusReg;
326         u32 BaseAddr;
327         s32 Count;
328
329         /*
330          * Assert validates the input arguments.
331          */
332         Xil_AssertNonvoid(InstancePtr != NULL);
333         Xil_AssertNonvoid(MsgPtr != NULL);
334         Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
335
336         BaseAddr = InstancePtr->Config.BaseAddress;
337         InstancePtr->RecvBufferPtr = MsgPtr;
338         InstancePtr->RecvByteCount = ByteCount;
339
340         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
341
342         /*
343          * Clear the interrupt status register.
344          */
345         IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
346         XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
347
348         /*
349          * Clear the status register.
350          */
351         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
352         XIicPs_WriteReg(BaseAddr, XIICPS_SR_OFFSET, StatusReg);
353
354         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
355         Count = InstancePtr->RecvByteCount;
356         while (Count > (s32)0) {
357
358                 /* Wait for master to put data */
359                 while ((StatusReg & XIICPS_SR_RXDV_MASK) == 0U) {
360                     StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
361
362                         /*
363                          * If master terminates the transfer before we get all
364                          * the data or the master tries to read from us,
365                          * it is an error.
366                          */
367                         IntrStatusReg = XIicPs_ReadReg(BaseAddr,
368                                                 XIICPS_ISR_OFFSET);
369                         if (((IntrStatusReg & (XIICPS_IXR_DATA_MASK |
370                                         XIICPS_IXR_COMP_MASK))!=0x0U) &&
371                                 ((StatusReg & XIICPS_SR_RXDV_MASK) == 0U) &&
372                                 ((InstancePtr->RecvByteCount > 0) != 0x0U)) {
373
374                                 return (s32)XST_FAILURE;
375                         }
376
377                         /*
378                          * Clear the interrupt status register.
379                          */
380                         XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET,
381                         IntrStatusReg);
382                 }
383
384                 /*
385                  * Read all data from FIFO.
386                  */
387                 while (((StatusReg & XIICPS_SR_RXDV_MASK)!=0x0U) &&
388                          ((InstancePtr->RecvByteCount > 0) != 0x0U)){
389
390                         XIicPs_RecvByte(InstancePtr);
391
392                         StatusReg = XIicPs_ReadReg(BaseAddr,
393                                 XIICPS_SR_OFFSET);
394                 }
395                 Count = InstancePtr->RecvByteCount;
396         }
397
398         return (s32)XST_SUCCESS;
399 }
400
401 /*****************************************************************************/
402 /**
403 * The interrupt handler for slave mode. It does the protocol handling for
404 * the interrupt-driven transfers.
405 *
406 * Completion events and errors are signaled to upper layer for proper
407 * handling.
408 *
409 * <pre>
410 *
411 * The interrupts that are handled are:
412 * - DATA
413 *       If the instance is sending, it means that the master wants to read more
414 *       data from us. Send more data, and check whether we are done with this
415 *       send.
416 *
417 *       If the instance is receiving, it means that the master has writen
418 *       more data to us. Receive more data, and check whether we are done with
419 *       with this receive.
420 *
421 * - COMP
422 *       This marks that stop sequence has been sent from the master, transfer
423 *       is about to terminate. However, for receiving, the master may have
424 *       written us some data, so receive that first.
425 *
426 *       It is an error if the amount of transfered data is less than expected.
427 *
428 * - NAK
429 *       This marks that master does not want our data. It is for send only.
430 *
431 * - Other interrupts
432 *       These interrupts are marked as error.
433 *
434 * </pre>
435 *
436 * @param        InstancePtr is a pointer to the XIicPs instance.
437 *
438 * @return       None.
439 *
440 * @note         None.
441 *
442 ****************************************************************************/
443 void XIicPs_SlaveInterruptHandler(XIicPs *InstancePtr)
444 {
445         u32 IntrStatusReg;
446         u32 IsSend = 0U;
447         u32 StatusEvent = 0U;
448         s32 LeftOver;
449         u32 BaseAddr;
450
451         /*
452          * Assert validates the input arguments.
453          */
454         Xil_AssertVoid(InstancePtr != NULL);
455         Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
456
457         BaseAddr = InstancePtr->Config.BaseAddress;
458
459         /*
460          * Read the Interrupt status register.
461          */
462         IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
463
464         /*
465          * Write the status back to clear the interrupts so no events are missed
466          * while processing this interrupt.
467          */
468         XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);
469
470         /*
471          * Use the Mask register AND with the Interrupt Status register so
472          * disabled interrupts are not processed.
473          */
474         IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, XIICPS_IMR_OFFSET));
475
476         /*
477          * Determine whether the device is sending.
478          */
479         if (InstancePtr->RecvBufferPtr == NULL) {
480                 IsSend = 1U;
481         }
482
483         /* Data interrupt
484          *
485          * This means master wants to do more data transfers.
486          * Also check for completion of transfer, signal upper layer if done.
487          */
488         if ((u32)0U != (IntrStatusReg & XIICPS_IXR_DATA_MASK)) {
489                 if (IsSend != 0x0U) {
490                         LeftOver = TransmitFifoFill(InstancePtr);
491                                 /*
492                                  * We may finish send here
493                                  */
494                                 if (LeftOver == 0) {
495                                         StatusEvent |=
496                                                 XIICPS_EVENT_COMPLETE_SEND;
497                                 }
498                 } else {
499                         LeftOver = SlaveRecvData(InstancePtr);
500
501                         /* We may finish the receive here */
502                         if (LeftOver == 0) {
503                                 StatusEvent |= XIICPS_EVENT_COMPLETE_RECV;
504                         }
505                 }
506         }
507
508         /*
509          * Complete interrupt.
510          *
511          * In slave mode, it means the master has done with this transfer, so
512          * we signal the application using completion event.
513          */
514         if (0U != (IntrStatusReg & XIICPS_IXR_COMP_MASK)) {
515                 if (IsSend != 0x0U) {
516                         if (InstancePtr->SendByteCount > 0) {
517                                 StatusEvent |= XIICPS_EVENT_ERROR;
518                         }else {
519                                 StatusEvent |= XIICPS_EVENT_COMPLETE_SEND;
520                         }
521                 } else {
522                         LeftOver = SlaveRecvData(InstancePtr);
523                         if (LeftOver > 0) {
524                                 StatusEvent |= XIICPS_EVENT_ERROR;
525                         } else {
526                                 StatusEvent |= XIICPS_EVENT_COMPLETE_RECV;
527                         }
528                 }
529         }
530
531         /*
532          * Nack interrupt, pass this information to application.
533          */
534         if (0U != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) {
535                 StatusEvent |= XIICPS_EVENT_NACK;
536         }
537
538         /*
539          * All other interrupts are treated as error.
540          */
541         if (0U != (IntrStatusReg & (XIICPS_IXR_TO_MASK |
542                                 XIICPS_IXR_RX_UNF_MASK |
543                                 XIICPS_IXR_TX_OVR_MASK |
544                                 XIICPS_IXR_RX_OVR_MASK))){
545
546                 StatusEvent |= XIICPS_EVENT_ERROR;
547         }
548
549         /*
550          * Signal application if there are any events.
551          */
552         if (0U != StatusEvent) {
553                 InstancePtr->StatusHandler(InstancePtr->CallBackRef,
554                                            StatusEvent);
555         }
556 }
557
558 /*****************************************************************************/
559 /*
560 *
561 * This function handles continuation of receiving data. It is invoked
562 * from interrupt handler.
563 *
564 * @param        InstancePtr is a pointer to the XIicPs instance.
565 *
566 * @return       Number of bytes still expected by the instance.
567 *
568 * @note         None.
569 *
570 ****************************************************************************/
571 static s32 SlaveRecvData(XIicPs *InstancePtr)
572 {
573         u32 StatusReg;
574         u32 BaseAddr;
575
576         BaseAddr = InstancePtr->Config.BaseAddress;
577
578         StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
579
580         while (((StatusReg & XIICPS_SR_RXDV_MASK)!=0x0U) &&
581                         ((InstancePtr->RecvByteCount > 0) != 0x0U)) {
582                 XIicPs_RecvByte(InstancePtr);
583                 StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);
584         }
585
586         return InstancePtr->RecvByteCount;
587 }