Root/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c

1/*******************************************************************************
2Copyright (C) Marvell International Ltd. and its affiliates
3
4This software file (the "File") is owned and distributed by Marvell
5International Ltd. and/or its affiliates ("Marvell") under the following
6alternative licensing terms. Once you have made an election to distribute the
7File under one of the following license alternatives, please (i) delete this
8introductory statement regarding license alternatives, (ii) delete the two
9license alternatives that you have not elected to use and (iii) preserve the
10Marvell copyright notice above.
11
12********************************************************************************
13Marvell Commercial License Option
14
15If you received this File from Marvell and you have entered into a commercial
16license agreement (a "Commercial License") with Marvell, the File is licensed
17to you under the terms of the applicable Commercial License.
18
19********************************************************************************
20Marvell GPL License Option
21
22If you received this File from Marvell, you may opt to use, redistribute and/or
23modify this File in accordance with the terms and conditions of the General
24Public License Version 2, June 1991 (the "GPL License"), a copy of which is
25available along with the File in the license.txt file or by writing to the Free
26Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
27on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
28
29THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
30WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
31DISCLAIMED. The GPL License provides additional details about this warranty
32disclaimer.
33********************************************************************************
34Marvell BSD License Option
35
36If you received this File from Marvell, you may opt to use, redistribute and/or
37modify this File under the following licensing terms.
38Redistribution and use in source and binary forms, with or without modification,
39are 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
52THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
53ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
56ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
59ANY 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
61SOFTWARE, 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********************************************************************************/
86static 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********************************************************************************/
155static 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*******************************************************************************/
213MV_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*******************************************************************************/
259MV_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********************************************************************************/
323MV_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********************************************************************************/
348MV_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*******************************************************************************/
376MV_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*******************************************************************************/
448MV_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*******************************************************************************/
523MV_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
577

Archive Download this file



interactive