/**
* \file spi.c
*
* \brief Spi Initialization functions. And a funciton to copy data from Flash
* to the given address.
*
*/
/*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "debug.h"
#include "mcspi.h"
#include "bl.h"
#include "bl_platform.h"
#include "bl_spi.h"
#include "uartStdio.h"
/******************************************************************************
** Macro Defination
*******************************************************************************/
#define CHAR_LENGTH 0x8
#define MCSPI_IN_CLK 48000000
//#define MCSPI_OUT_CLK 6000000
//#define MCSPI_OUT_CLK 24000000
#define MCSPI_OUT_CLK 48000000
/* flash data read command */
#define SPI_FLASH_READ 0x03
/******************************************************************************
** Local Declaration
*******************************************************************************/
static void McSPITransfer(unsigned char *p_tx,
unsigned char *p_rx,
unsigned int len);
static void McSPIFastRead(unsigned char *p_rx, unsigned int len);
/*
* \brief - SPI Configures.
* \param - none.
*
* \return none.
*/
void SPIConfigure(void)
{
unsigned int retVal = 0;
/* Reset the McSPI instance.*/
McSPIReset(SPI_BASE);
/* Enable chip select pin.*/
McSPICSEnable(SPI_BASE);
/* Enable master mode of operation.*/
McSPIMasterModeEnable(SPI_BASE);
/* Perform the necessary configuration for master mode.*/
retVal = McSPIMasterModeConfig(SPI_BASE, MCSPI_SINGLE_CH, MCSPI_TX_RX_MODE,\
MCSPI_DATA_LINE_COMM_MODE_6, SPI_CHAN);
// XXXX this is needed until I rework the spi bus
// MCSPI_DATA_LINE_COMM_MODE_1, SPI_CHAN);
/*
** If combination of trm and IS,DPE0 and DPE1 is not valid then retVal is
** false.
*/
if(!retVal)
{
UARTPuts("Invalid McSPI config \r\n", -1);
UARTPuts("Aborting Boot\r\n", -1);
BootAbort();
}
/*
** Default granularity is used. Also as per my understanding clock mode
** 0 is proper.
*/
McSPIClkConfig(SPI_BASE, MCSPI_IN_CLK, MCSPI_OUT_CLK,
SPI_CHAN, MCSPI_CLK_MODE_0);
/* Configure the word length.*/
McSPIWordLengthSet(SPI_BASE, MCSPI_WORD_LENGTH(8), SPI_CHAN);
/* Set polarity of SPIEN to low.*/
McSPICSPolarityConfig(SPI_BASE, MCSPI_CS_POL_LOW, SPI_CHAN);
/* Enable the transmitter FIFO of McSPI peripheral.*/
McSPITxFIFOConfig(SPI_BASE, MCSPI_TX_FIFO_ENABLE, SPI_CHAN);
/* Enable the receiver FIFO of McSPI peripheral.*/
McSPIRxFIFOConfig(SPI_BASE, MCSPI_RX_FIFO_ENABLE, SPI_CHAN);
}
/**
* \brief - Reads bytes from SPI Flash.
* \param - offset - SPI Flash address.\n.
* \param - size - Indicates the total size needs to be read from flash.\n.
* \param - dst - Destination address where data needs to be copy.\n.
*
* \return none
**/
void BlSPIReadFlash (unsigned int offset,
unsigned int size,
unsigned char *dst)
{
unsigned char tx_data;
unsigned char rx_data;
unsigned char addr[3];
unsigned int len;
/* The process of reading the data from the flash involves asserting
* proper chipselect line, asserting CSHOLD, selecting correct data format.
* Then the flash needs a command to indicate start of read and then
* any number of bytes can be read. After the required number of bytes
* are read, the CS needs to be de-asserted to indicate the end of transfer
*/
McSPICSAssert(SPI_BASE, SPI_CHAN);
/* Enable the McSPI channel for communication.*/
McSPIChannelEnable(SPI_BASE, SPI_CHAN);
/* Send read command to the flash (one byte) */
tx_data = SPI_FLASH_READ;
McSPITransfer(&tx_data, &rx_data, 1);
/* Send the address to start reading from (3 bytes) */
addr[0] = (unsigned char)(offset >> 16);
addr[1] = (unsigned char)(offset >> 8);
addr[2] = (unsigned char)offset;
len = 0;
while (len < sizeof(addr))
{
McSPITransfer(&addr[len], &rx_data, 1);
len++;
}
/* Read all the bytes */
McSPIFastRead(dst, size);
/* Force SPIEN line to the inactive state.*/
McSPICSDeAssert(SPI_BASE, SPI_CHAN);
/* Disable the McSPI channel.*/
McSPIChannelDisable(SPI_BASE, SPI_CHAN);
}
/**
* \brief - Spi Write and Read.
* \param - p_tx - SPI transmit data address.\n.
* \param - p_rx - SPI data reception address.\n.
* \param - len - Indicates the total length the read and write has to do.\n.
*
* \return none
**/
static void McSPITransfer(unsigned char *p_tx, unsigned char *p_rx,
unsigned int len)
{
while(len)
{
/* Wait till TX is empty. */
while(MCSPI_INT_TX_EMPTY(SPI_CHAN) !=
(McSPIIntStatusGet(SPI_BASE) & MCSPI_INT_TX_EMPTY(SPI_CHAN)));
McSPITransmitData(SPI_BASE, *p_tx, SPI_CHAN);
p_tx++;
/* Wait till the DATA in RX. */
while(MCSPI_INT_RX_FULL(SPI_CHAN) !=
(McSPIIntStatusGet(SPI_BASE) & MCSPI_INT_RX_FULL(SPI_CHAN)));
*p_rx = McSPIReceiveData(SPI_BASE, SPI_CHAN);
// XXXX without clearing the status then
McSPIIntStatusClear(SPI_BASE, MCSPI_INT_RX_FULL(SPI_CHAN));
p_rx++;
len--;
}
}
static void McSPIFastRead(unsigned char *p_rx, unsigned int len)
{
unsigned int tx_len = 0;
unsigned int rx_len = 0;
unsigned int *ptr = (unsigned int *)p_rx;
/* len must by divisable by 32 bit words for mutliple word access */
ASSERT(len & 0x3 == 0);
McSPITurboModeEnable(SPI_BASE, SPI_CHAN);
McSPIMultipleWordAccessConfig(SPI_BASE, MCSPI_MOA_ENABLE);
unsigned int fill_len = len;
if (fill_len > 32) {
fill_len = 32;
}
/* Prime the TX FIFO with dummy data */
while (tx_len < fill_len && !(McSPIChannelStatusGet(SPI_BASE, SPI_CHAN) & MCSPI_CH_TXFFF)) {
McSPITransmitData(SPI_BASE, tx_len, SPI_CHAN);
tx_len += 4;
}
int debug_done_break = 0;
while (rx_len < len) {
// XXXX this loop gets stuck when reading the last word, count is used as a workaround to break out of
// the loop. even though RXFFE is true (indicating the fifo is empty), it appears that the last word is
// ready to read.
unsigned int count = 0;
while (McSPIChannelStatusGet(SPI_BASE, SPI_CHAN) & MCSPI_CH_RXFFE) {
if (count++ > 100) {
debug_done_break = rx_len;
break;
}
}
// XXXX it be possible to use the rx full interrupt status to detect when a byte is available to read
// however this never seems to block. setting varies values for AFL and AEL in MCSPI_XFERLEVEL do not
// appear to make any difference.
//while (MCSPI_INT_RX_FULL(SPI_CHAN) != McSPIIntStatusGet(SPI_BASE) & MCSPI_INT_RX_FULL(SPI_CHAN));
*ptr = McSPIReceiveData(SPI_BASE, SPI_CHAN);
ptr++;
rx_len += 4;
/* Keep the TX FIFO filled with dummy data */
if (tx_len < len) {
McSPITransmitData(SPI_BASE, tx_len, SPI_CHAN);
tx_len += 4;
}
}
if (debug_done_break) {
UARTPuts("done break ", -1); UARTPutHexNum(debug_done_break); UARTPuts("\n", -1);
}
McSPIMultipleWordAccessConfig(SPI_BASE, MCSPI_MOA_DISABLE);
McSPITurboModeDisable(SPI_BASE, SPI_CHAN);
}
/***************************** End Of File ***********************************/