rename target/linux/generic-2.6 to generic
[15.05/openwrt.git] / target / linux / generic / files / crypto / ocf / kirkwood / mvHal / mv_hal / spi / mvSpi.c
1 /*******************************************************************************
2 Copyright (C) Marvell International Ltd. and its affiliates
3
4 This software file (the "File") is owned and distributed by Marvell
5 International Ltd. and/or its affiliates ("Marvell") under the following
6 alternative licensing terms.  Once you have made an election to distribute the
7 File under one of the following license alternatives, please (i) delete this
8 introductory statement regarding license alternatives, (ii) delete the two
9 license alternatives that you have not elected to use and (iii) preserve the
10 Marvell copyright notice above.
11
12 ********************************************************************************
13 Marvell Commercial License Option
14
15 If you received this File from Marvell and you have entered into a commercial
16 license agreement (a "Commercial License") with Marvell, the File is licensed
17 to you under the terms of the applicable Commercial License.
18
19 ********************************************************************************
20 Marvell GPL License Option
21
22 If you received this File from Marvell, you may opt to use, redistribute and/or
23 modify this File in accordance with the terms and conditions of the General
24 Public License Version 2, June 1991 (the "GPL License"), a copy of which is
25 available along with the File in the license.txt file or by writing to the Free
26 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
27 on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
28
29 THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
30 WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
31 DISCLAIMED.  The GPL License provides additional details about this warranty
32 disclaimer.
33 ********************************************************************************
34 Marvell BSD License Option
35
36 If you received this File from Marvell, you may opt to use, redistribute and/or
37 modify this File under the following licensing terms.
38 Redistribution and use in source and binary forms, with or without modification,
39 are permitted provided that the following conditions are met:
40
41     *   Redistributions of source code must retain the above copyright notice,
42             this list of conditions and the following disclaimer.
43
44     *   Redistributions in binary form must reproduce the above copyright
45         notice, this list of conditions and the following disclaimer in the
46         documentation and/or other materials provided with the distribution.
47
48     *   Neither the name of Marvell nor the names of its contributors may be
49         used to endorse or promote products derived from this software without
50         specific prior written permission.
51
52 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
53 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
56 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
59 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62
63 *******************************************************************************/
64
65 #include "spi/mvSpi.h"
66 #include "spi/mvSpiSpec.h"
67
68 #include "ctrlEnv/mvCtrlEnvLib.h"
69
70 /* #define MV_DEBUG */
71 #ifdef MV_DEBUG
72 #define DB(x) x
73 #define mvOsPrintf printf
74 #else
75 #define DB(x)
76 #endif
77
78
79 /*******************************************************************************
80 * mvSpi16bitDataTxRx - Transmt and receive data
81 *
82 * DESCRIPTION:
83 *       Tx data and block waiting for data to be transmitted
84 *
85 ********************************************************************************/
86 static MV_STATUS mvSpi16bitDataTxRx (MV_U16 txData, MV_U16 * pRxData)
87 {
88     MV_U32 i;
89     MV_BOOL ready = MV_FALSE;
90
91     /* First clear the bit in the interrupt cause register */
92     MV_REG_WRITE(MV_SPI_INT_CAUSE_REG, 0x0);
93
94     /* Transmit data */
95     MV_REG_WRITE(MV_SPI_DATA_OUT_REG, MV_16BIT_LE(txData));
96
97     /* wait with timeout for memory ready */
98     for (i=0; i<MV_SPI_WAIT_RDY_MAX_LOOP; i++)
99     {
100         if (MV_REG_READ(MV_SPI_INT_CAUSE_REG))
101         {
102             ready = MV_TRUE;
103             break;
104         }
105 #ifdef MV_SPI_SLEEP_ON_WAIT
106         mvOsSleep(1);
107 #endif /* MV_SPI_SLEEP_ON_WAIT */
108     }
109
110     if (!ready)
111         return MV_TIMEOUT;
112
113     /* check that the RX data is needed */
114     if (pRxData)
115     {
116         if ((MV_U32)pRxData &  0x1) /* check if address is not alligned to 16bit */
117         {
118 #if defined(MV_CPU_LE)
119                 /* perform the data write to the buffer in two stages with 8bit each */
120                 MV_U8 * bptr = (MV_U8*)pRxData;
121                 MV_U16 data = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG));
122                 *bptr = (data & 0xFF);
123                 ++bptr;
124                 *bptr = ((data >> 8) & 0xFF);
125
126 #elif defined(MV_CPU_BE)
127
128                 /* perform the data write to the buffer in two stages with 8bit each */
129                 MV_U8 * bptr = (MV_U8 *)pRxData;
130                 MV_U16 data = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG));
131                 *bptr = ((data >> 8) & 0xFF);
132                 ++bptr;
133                 *bptr = (data & 0xFF);
134
135 #else
136     #error "CPU endianess isn't defined!\n"
137 #endif
138
139         }
140         else
141                 *pRxData = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG));
142     }
143
144     return MV_OK;
145 }
146
147
148 /*******************************************************************************
149 * mvSpi8bitDataTxRx - Transmt and receive data (8bits)
150 *
151 * DESCRIPTION:
152 *       Tx data and block waiting for data to be transmitted
153 *
154 ********************************************************************************/
155 static MV_STATUS mvSpi8bitDataTxRx (MV_U8 txData, MV_U8 * pRxData)
156 {
157     MV_U32 i;
158     MV_BOOL ready = MV_FALSE;
159
160     /* First clear the bit in the interrupt cause register */
161     MV_REG_WRITE(MV_SPI_INT_CAUSE_REG, 0x0);
162
163     /* Transmit data */
164     MV_REG_WRITE(MV_SPI_DATA_OUT_REG, txData);
165
166     /* wait with timeout for memory ready */
167     for (i=0; i<MV_SPI_WAIT_RDY_MAX_LOOP; i++)
168     {
169         if (MV_REG_READ(MV_SPI_INT_CAUSE_REG))
170         {
171             ready = MV_TRUE;
172             break;
173         }
174 #ifdef MV_SPI_SLEEP_ON_WAIT
175         mvOsSleep(1);
176 #endif /* MV_SPI_SLEEP_ON_WAIT */
177     }
178
179     if (!ready)
180         return MV_TIMEOUT;
181
182     /* check that the RX data is needed */
183     if (pRxData)
184         *pRxData = MV_REG_READ(MV_SPI_DATA_IN_REG);
185
186     return MV_OK;
187 }
188
189 /*
190 #####################################################################################
191 #####################################################################################
192 */
193
194 /*******************************************************************************
195 * mvSpiInit - Initialize the SPI controller
196 *
197 * DESCRIPTION:
198 *       Perform the neccessary initialization in order to be able to send an
199 *               receive over the SPI interface.
200 *
201 * INPUT:
202 *       serialBaudRate: Baud rate (SPI clock frequency)
203 *               use16BitMode: Whether to use 2bytes (MV_TRUE) or 1bytes (MV_FALSE)
204 *
205 * OUTPUT:
206 *       None.
207 *
208 * RETURN:
209 *       Success or Error code.
210 *
211 *
212 *******************************************************************************/
213 MV_STATUS mvSpiInit     (MV_U32 serialBaudRate)
214 {
215     MV_STATUS ret;
216
217     /* Set the serial clock */
218     if ((ret = mvSpiBaudRateSet(serialBaudRate)) != MV_OK)
219         return ret;
220
221     /* For devices in which the SPI is muxed on the MPP with other interfaces*/
222     mvMPPConfigToSPI();
223
224         /* Configure the default SPI mode to be 16bit */
225         MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
226
227         /* Fix ac timing on SPI in 6183, 6183L and 78x00 only */
228         if ( (mvCtrlModelGet() == MV_6183_DEV_ID) ||
229                  (mvCtrlModelGet() == MV_6183L_DEV_ID) ||
230                 (mvCtrlModelGet() == MV_78100_DEV_ID) ||
231                 (mvCtrlModelGet() == MV_78200_DEV_ID) ||
232                 (mvCtrlModelGet() == MV_76100_DEV_ID))
233             MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, BIT14);
234
235     /* Verify that the CS is deasserted */
236     mvSpiCsDeassert();
237
238     return MV_OK;
239 }
240
241 /*******************************************************************************
242 * mvSpiBaudRateSet - Set the Frequency of the SPI clock
243 *
244 * DESCRIPTION:
245 *       Set the Prescale bits to adapt to the requested baud rate (the clock
246 *       used for thr SPI).
247 *
248 * INPUT:
249 *       serialBaudRate: Baud rate (SPI clock frequency)
250 *
251 * OUTPUT:
252 *       None.
253 *
254 * RETURN:
255 *       Success or Error code.
256 *
257 *
258 *******************************************************************************/
259 MV_STATUS mvSpiBaudRateSet (MV_U32 serialBaudRate)
260 {
261     MV_U8 i;
262         /* MV_U8 preScale[32] = {1, 1, 2, 3, 4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
263                                                   2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
264         */
265         MV_U8 preScale[14] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
266         MV_U8 bestPrescaleIndx = 100;
267         MV_U32 minBaudOffset = 0xFFFFFFFF;
268         MV_U32 cpuClk = mvBoardTclkGet(); /*mvCpuPclkGet();*/
269         MV_U32 tempReg;
270
271         /* Find the best prescale configuration - less or equal */
272         for (i=0; i<14; i++)
273         {
274                 /* check for higher - irrelevent */
275                 if ((cpuClk / preScale[i]) > serialBaudRate)
276                         continue;
277
278                 /* check for exact fit */
279                 if ((cpuClk / preScale[i]) == serialBaudRate)
280                 {
281                         bestPrescaleIndx = i;
282                         break;
283                 }
284
285                 /* check if this is better than the previous one */
286                 if ((serialBaudRate - (cpuClk / preScale[i])) < minBaudOffset)
287                 {
288                         minBaudOffset = (serialBaudRate - (cpuClk / preScale[i]));
289                         bestPrescaleIndx = i;
290                 }
291         }
292
293         if (bestPrescaleIndx > 14)
294     {
295         mvOsPrintf("%s ERROR: SPI baud rate prescale error!\n", __FUNCTION__);
296                 return MV_OUT_OF_RANGE;
297     }
298
299         /* configure the Prescale */
300         tempReg = MV_REG_READ(MV_SPI_IF_CONFIG_REG);
301         tempReg = ((tempReg & ~MV_SPI_CLK_PRESCALE_MASK) | (bestPrescaleIndx + 0x12));
302         MV_REG_WRITE(MV_SPI_IF_CONFIG_REG, tempReg);
303
304     return MV_OK;
305 }
306
307 /*******************************************************************************
308 * mvSpiCsAssert - Assert the Chip Select pin indicating a new transfer
309 *
310 * DESCRIPTION:
311 *       Assert The chip select - used to select an external SPI device
312 *
313 * INPUT:
314 *       None.
315 *
316 * OUTPUT:
317 *       None.
318 *
319 * RETURN:
320 *       Success or Error code.
321 *
322 ********************************************************************************/
323 MV_VOID mvSpiCsAssert(MV_VOID)
324 {
325     /* For devices in which the SPI is muxed on the MPP with other interfaces*/
326     mvMPPConfigToSPI();
327     mvOsUDelay(1);
328     MV_REG_BIT_SET(MV_SPI_IF_CTRL_REG, MV_SPI_CS_ENABLE_MASK);
329 }
330
331 /*******************************************************************************
332 * mvSpiCsDeassert - DeAssert the Chip Select pin indicating the end of a
333 *                                 SPI transfer sequence
334 *
335 * DESCRIPTION:
336 *       DeAssert the chip select pin
337 *
338 * INPUT:
339 *       None.
340 *
341 * OUTPUT:
342 *       None.
343 *
344 * RETURN:
345 *       Success or Error code.
346 *
347 ********************************************************************************/
348 MV_VOID mvSpiCsDeassert(MV_VOID)
349 {
350         MV_REG_BIT_RESET(MV_SPI_IF_CTRL_REG, MV_SPI_CS_ENABLE_MASK);
351
352     /* For devices in which the SPI is muxed on the MPP with other interfaces*/
353     mvMPPConfigToDefault();
354 }
355
356 /*******************************************************************************
357 * mvSpiRead - Read a buffer over the SPI interface
358 *
359 * DESCRIPTION:
360 *       Receive (read) a buffer over the SPI interface in 16bit chunks. If the
361 *               buffer size is odd, then the last chunk will be 8bits. Chip select is not
362 *       handled at this level.
363 *
364 * INPUT:
365 *               pRxBuff: Pointer to the buffer to hold the received data
366 *               buffSize: length of the pRxBuff
367 *
368 * OUTPUT:
369 *               pRxBuff: Pointer to the buffer with the received data
370 *
371 * RETURN:
372 *       Success or Error code.
373 *
374 *
375 *******************************************************************************/
376 MV_STATUS mvSpiRead     (MV_U8* pRxBuff, MV_U32 buffSize)
377 {
378     MV_STATUS ret;
379         MV_U32 bytesLeft = buffSize;
380         MV_U16* rxPtr = (MV_U16*)pRxBuff;
381
382     /* check for null parameters */
383     if (pRxBuff == NULL)
384     {
385         mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
386         return MV_BAD_PARAM;
387     }
388
389     /* Check that the buffer pointer and the buffer size are 16bit aligned */
390     if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pRxBuff & 1) == 0))
391     {
392         /* Verify that the SPI mode is in 16bit mode */
393         MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
394
395         /* TX/RX as long we have complete 16bit chunks */
396         while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE)
397         {
398                 /* Transmitted and wait for the transfer to be completed */
399                 if ((ret = mvSpi16bitDataTxRx(MV_SPI_DUMMY_WRITE_16BITS, rxPtr)) != MV_OK)
400                         return ret;
401
402                 /* increment the pointers */
403                 rxPtr++;
404                 bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE;
405         }
406
407     }
408     else
409     {
410         /* Verify that the SPI mode is in 8bit mode */
411         MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
412
413         /* TX/RX in 8bit chanks */
414         while (bytesLeft > 0)
415         {
416                 /* Transmitted and wait for the transfer to be completed */
417                 if ((ret = mvSpi8bitDataTxRx(MV_SPI_DUMMY_WRITE_8BITS, pRxBuff)) != MV_OK)
418                         return ret;
419                 /* increment the pointers */
420                 pRxBuff++;
421                 bytesLeft--;
422         }
423     }
424
425         return MV_OK;
426 }
427
428 /*******************************************************************************
429 * mvSpiWrite - Transmit a buffer over the SPI interface
430 *
431 * DESCRIPTION:
432 *       Transmit a buffer over the SPI interface in 16bit chunks. If the
433 *               buffer size is odd, then the last chunk will be 8bits. No chip select
434 *       action is taken.
435 *
436 * INPUT:
437 *               pTxBuff: Pointer to the buffer holding the TX data
438 *               buffSize: length of the pTxBuff
439 *
440 * OUTPUT:
441 *       None.
442 *
443 * RETURN:
444 *       Success or Error code.
445 *
446 *
447 *******************************************************************************/
448 MV_STATUS mvSpiWrite(MV_U8* pTxBuff, MV_U32 buffSize)
449 {
450     MV_STATUS ret;
451         MV_U32 bytesLeft = buffSize;
452         MV_U16* txPtr = (MV_U16*)pTxBuff;
453
454     /* check for null parameters */
455     if (pTxBuff == NULL)
456     {
457         mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
458         return MV_BAD_PARAM;
459     }
460
461     /* Check that the buffer pointer and the buffer size are 16bit aligned */
462     if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pTxBuff & 1) == 0))
463     {
464         /* Verify that the SPI mode is in 16bit mode */
465         MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
466
467         /* TX/RX as long we have complete 16bit chunks */
468         while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE)
469         {
470         /* Transmitted and wait for the transfer to be completed */
471                 if ((ret = mvSpi16bitDataTxRx(*txPtr, NULL)) != MV_OK)
472                         return ret;
473
474                 /* increment the pointers */
475                 txPtr++;
476                 bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE;
477         }
478     }
479     else
480     {
481
482         /* Verify that the SPI mode is in 8bit mode */
483         MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
484
485         /* TX/RX in 8bit chanks */
486         while (bytesLeft > 0)
487         {
488                 /* Transmitted and wait for the transfer to be completed */
489                 if ((ret = mvSpi8bitDataTxRx(*pTxBuff, NULL)) != MV_OK)
490                         return ret;
491
492                 /* increment the pointers */
493                 pTxBuff++;
494                 bytesLeft--;
495         }
496     }
497
498         return MV_OK;
499 }
500
501
502 /*******************************************************************************
503 * mvSpiReadWrite - Read and Write a buffer simultanuosely
504 *
505 * DESCRIPTION:
506 *       Transmit and receive a buffer over the SPI in 16bit chunks. If the
507 *               buffer size is odd, then the last chunk will be 8bits. The SPI chip
508 *       select is not handled implicitely.
509 *
510 * INPUT:
511 *       pRxBuff: Pointer to the buffer to write the RX info in
512 *               pTxBuff: Pointer to the buffer holding the TX info
513 *               buffSize: length of both the pTxBuff and pRxBuff
514 *
515 * OUTPUT:
516 *       pRxBuff: Pointer of the buffer holding the RX data
517 *
518 * RETURN:
519 *       Success or Error code.
520 *
521 *
522 *******************************************************************************/
523 MV_STATUS mvSpiReadWrite(MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize)
524 {
525     MV_STATUS ret;
526     MV_U32 bytesLeft = buffSize;
527     MV_U16* txPtr = (MV_U16*)pTxBuff;
528     MV_U16* rxPtr = (MV_U16*)pRxBuff;
529
530     /* check for null parameters */
531     if ((pRxBuff == NULL) || (pTxBuff == NULL))
532     {
533         mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
534         return MV_BAD_PARAM;
535     }
536
537     /* Check that the buffer pointer and the buffer size are 16bit aligned */
538     if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pTxBuff & 1) == 0) && (((MV_U32)pRxBuff & 1) == 0))
539     {
540         /* Verify that the SPI mode is in 16bit mode */
541         MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
542
543         /* TX/RX as long we have complete 16bit chunks */
544         while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE)
545         {
546         /* Transmitted and wait for the transfer to be completed */
547                 if ((ret = mvSpi16bitDataTxRx(*txPtr, rxPtr)) != MV_OK)
548                         return ret;
549
550                 /* increment the pointers */
551                 txPtr++;
552                 rxPtr++;
553                 bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE;
554         }
555     }
556     else
557     {
558         /* Verify that the SPI mode is in 8bit mode */
559         MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
560
561         /* TX/RX in 8bit chanks */
562         while (bytesLeft > 0)
563         {
564                 /* Transmitted and wait for the transfer to be completed */
565                 if ( (ret = mvSpi8bitDataTxRx(*pTxBuff, pRxBuff) ) != MV_OK)
566                         return ret;
567                 pRxBuff++;
568                 pTxBuff++;
569                 bytesLeft--;
570         }
571     }
572
573         return MV_OK;
574 }
575
576