spi_flash.c revision 174877
175584Sru/******************************************************************************
275584Sru *
375584Sru * Filename: spi_flash.c
4104862Sru *
575584Sru * Instantiation of SPI flash control routines supporting AT45DB161B
675584Sru *
775584Sru * Revision information:
875584Sru *
975584Sru * 17JAN2005	kb_admin	initial creation
1075584Sru *				adapted from external sources
1175584Sru *				tested for basic operation only!!!
1275584Sru *
1375584Sru * BEGIN_KBDD_BLOCK
1475584Sru * No warranty, expressed or implied, is included with this software.  It is
15104862Sru * provided "AS IS" and no warranty of any kind including statutory or aspects
1675584Sru * relating to merchantability or fitness for any purpose is provided.  All
1775584Sru * intellectual property rights of others is maintained with the respective
1875584Sru * owners.  This software is not copyrighted and is intended for reference
1975584Sru * only.
2075584Sru * END_BLOCK
2175584Sru *
22104862Sru * $FreeBSD: head/sys/boot/arm/at91/libat91/spi_flash.c 174877 2007-12-23 14:46:30Z ticso $
2375584Sru *****************************************************************************/
2475584Sru
2575584Sru#include "at91rm9200.h"
26104862Sru#include "spi_flash.h"
2775584Sru#include "lib.h"
28104862Sru
2975584Sru/*********************** PRIVATE FUNCTIONS/DATA ******************************/
3075584Sru
3175584Sru
3275584Srustatic spiCommand_t	spi_command;
3375584Srustatic char		tx_commandBuffer[8], rx_commandBuffer[8];
3475584Sru
3575584Sru/*
3675584Sru * .KB_C_FN_DEFINITION_START
3775584Sru * void SendCommand(spiCommand_t *pCommand)
3875584Sru *  Private function sends 8-bit value to the device and returns the 8-bit
3975584Sru * value in response.
4075584Sru * .KB_C_FN_DEFINITION_END
4175584Sru */
4275584Srustatic void
4375584SruSendCommand(spiCommand_t *pCommand)
4475584Sru{
4575584Sru	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
4675584Sru
4775584Sru	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
4875584Sru
4975584Sru	pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
5075584Sru	pSPI->SPI_RCR = pCommand->rx_cmd_size;
5175584Sru	pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
5275584Sru	pSPI->SPI_TCR = pCommand->tx_cmd_size;
5375584Sru
5475584Sru	pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
5575584Sru	pSPI->SPI_TNCR = pCommand->tx_data_size;
5675584Sru	pSPI->SPI_RNPR = (unsigned)pCommand->rx_data;
5775584Sru	pSPI->SPI_RNCR = pCommand->rx_data_size;
5875584Sru
5975584Sru	pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
6075584Sru
6175584Sru	// wait for completion
6275584Sru	while (!(pSPI->SPI_SR & AT91C_SPI_SPENDRX))
6375584Sru		Delay(700);
6475584Sru}
6575584Sru
6675584Sru
6775584Sru/*
6875584Sru * .KB_C_FN_DEFINITION_START
6975584Sru * char GetFlashStatus(void)
7075584Sru *  Private function to return device status.
7175584Sru * .KB_C_FN_DEFINITION_END
7275584Sru */
7375584Srustatic char
7475584SruGetFlashStatus(void)
7575584Sru{
7675584Sru	p_memset((char *)&spi_command, 0, sizeof(spi_command));
7775584Sru	p_memset(tx_commandBuffer, 0, 8);
7875584Sru	tx_commandBuffer[0] = STATUS_REGISTER_READ;
7975584Sru	p_memset(rx_commandBuffer, 0, 8);
8075584Sru	spi_command.tx_cmd = tx_commandBuffer;
81104862Sru	spi_command.rx_cmd = rx_commandBuffer;
8275584Sru	spi_command.rx_cmd_size = 2;
8375584Sru	spi_command.tx_cmd_size = 2;
8475584Sru	SendCommand(&spi_command);
8575584Sru	return (rx_commandBuffer[1]);
8675584Sru}
8775584Sru
8875584Sru/*
8975584Sru * .KB_C_FN_DEFINITION_START
9075584Sru * void WaitForDeviceReady(void)
9175584Sru *  Private function to poll until the device is ready for next operation.
9275584Sru * .KB_C_FN_DEFINITION_END
9375584Sru */
9475584Srustatic void
9575584SruWaitForDeviceReady(void)
9675584Sru{
9775584Sru	while (!(GetFlashStatus() & 0x80)) ;
9875584Sru}
9975584Sru
10075584Sru/*************************** GLOBAL FUNCTIONS ********************************/
10175584Sru
10275584Sru
10375584Sru/*
10475584Sru * .KB_C_FN_DEFINITION_START
10575584Sru * void SPI_ReadFlash(unsigned flash_addr, unsigned dest_addr, unsigned size)
10675584Sru *  Global function to read the SPI flash device using the continuous read
10775584Sru * array command.
10875584Sru * .KB_C_FN_DEFINITION_END
10975584Sru */
11075584Sruvoid
11175584SruSPI_ReadFlash(unsigned flash_addr, char *dest_addr, unsigned size)
11275584Sru{
11375584Sru	unsigned	pageAddress, byteAddress;
11475584Sru
11575584Sru	// determine page address
11675584Sru	pageAddress = flash_addr / FLASH_PAGE_SIZE;
11775584Sru
11875584Sru	// determine byte address
11975584Sru	byteAddress = flash_addr % FLASH_PAGE_SIZE;
120104862Sru
12175584Sru	p_memset(tx_commandBuffer, 0, 8);
12275584Sru#ifdef BOOT_BWCT
12375584Sru	tx_commandBuffer[0] = 0xd2;
12475584Sru	tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
12575584Sru	tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
12675584Sru				((byteAddress >> 8) & 0x3);
12775584Sru	tx_commandBuffer[3] = byteAddress & 0xFF;
12875584Sru	spi_command.tx_cmd = tx_commandBuffer;
12975584Sru	spi_command.tx_cmd_size = 8;
13075584Sru	spi_command.tx_data_size = size;
13175584Sru	spi_command.tx_data = dest_addr;
13275584Sru
13375584Sru	p_memset(rx_commandBuffer, 0, 8);
13475584Sru	spi_command.rx_cmd = rx_commandBuffer;
13575584Sru	spi_command.rx_cmd_size = 8;
13675584Sru	spi_command.rx_data_size = size;
13775584Sru	spi_command.rx_data = dest_addr;
138104862Sru#else
13975584Sru	tx_commandBuffer[0] = CONTINUOUS_ARRAY_READ_HF;
14075584Sru	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
14175584Sru	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
142104862Sru				((byteAddress >> 8) & 0x7);
14375584Sru	tx_commandBuffer[3] = byteAddress & 0xFF;
14475584Sru	spi_command.tx_cmd = tx_commandBuffer;
14575584Sru	spi_command.tx_cmd_size = 5;
14675584Sru	spi_command.tx_data_size = size;
14775584Sru	spi_command.tx_data = dest_addr;
14875584Sru
14975584Sru	p_memset(rx_commandBuffer, 0, 8);
15075584Sru	spi_command.rx_cmd = rx_commandBuffer;
15175584Sru	spi_command.rx_cmd_size = 5;
15275584Sru	spi_command.rx_data_size = size;
15375584Sru	spi_command.rx_data = dest_addr;
15475584Sru#endif
15575584Sru
15675584Sru	SendCommand(&spi_command);
15775584Sru}
15875584Sru
15975584Sru
16075584Sru/*
16175584Sru * .KB_C_FN_DEFINITION_START
16275584Sru * void SPI_WriteFlash(unsigned flash_addr, unsigned src_addr, unsigned size)
16375584Sru *  Global function to program the SPI flash device.  Notice the warning
16475584Sru * provided in lower-level functions regarding corruption of data in non-
16575584Sru * page aligned write operations.
16675584Sru * .KB_C_FN_DEFINITION_END
16775584Sru */
16875584Sruvoid
16975584SruSPI_WriteFlash(unsigned flash_addr, char *src_addr, unsigned size)
17075584Sru{
17175584Sru	unsigned	pageAddress, byteAddress;
17275584Sru
17375584Sru	// determine page address
17475584Sru	pageAddress = flash_addr / FLASH_PAGE_SIZE;
17575584Sru
176104862Sru	// determine byte address
17775584Sru	byteAddress = flash_addr % FLASH_PAGE_SIZE;
17875584Sru
17975584Sru	p_memset(tx_commandBuffer, 0, 8);
18075584Sru#ifdef BOOT_BWCT
18175584Sru	tx_commandBuffer[0] = 0x82;
18275584Sru	tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
18375584Sru	tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
18475584Sru				((byteAddress >> 8) & 0x3);
18575584Sru	tx_commandBuffer[3] = (byteAddress & 0xFF);
18675584Sru#else
18775584Sru	tx_commandBuffer[0] = PROGRAM_THROUGH_BUFFER;
18875584Sru	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
18975584Sru	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
19075584Sru				((byteAddress >> 8) & 0x7);
19175584Sru	tx_commandBuffer[3] = (byteAddress & 0xFF);
19275584Sru#endif
19375584Sru
19475584Sru	p_memset(rx_commandBuffer, 0, 8);
19575584Sru
19675584Sru	spi_command.tx_cmd = tx_commandBuffer;
19775584Sru	spi_command.rx_cmd = rx_commandBuffer;
19875584Sru	spi_command.rx_cmd_size = 4;
19975584Sru	spi_command.tx_cmd_size = 4;
20075584Sru
20175584Sru	spi_command.tx_data_size = size;
20275584Sru	spi_command.tx_data = src_addr;
20375584Sru	spi_command.rx_data_size = size;
20475584Sru	spi_command.rx_data = src_addr;
20575584Sru
20675584Sru	SendCommand(&spi_command);
20775584Sru
208104862Sru	WaitForDeviceReady();
20975584Sru}
21075584Sru
21175584Sru/*
21275584Sru * .KB_C_FN_DEFINITION_START
21375584Sru * void SPI_InitFlash(void)
21475584Sru *  Global function to initialize the SPI flash device/accessor functions.
21575584Sru * .KB_C_FN_DEFINITION_END
21675584Sru */
217void
218SPI_InitFlash(void)
219{
220	AT91PS_PIO	pPio;
221	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
222	unsigned	value;
223
224	// enable CS0, CLK, MOSI, MISO
225	pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
226	pPio->PIO_ASR = AT91C_PA3_NPCS0 | AT91C_PA1_MOSI | AT91C_PA0_MISO |
227	    AT91C_PA2_SPCK;
228	pPio->PIO_PDR = AT91C_PA3_NPCS0 | AT91C_PA1_MOSI | AT91C_PA0_MISO |
229	    AT91C_PA2_SPCK;
230
231	// enable clocks to SPI
232	AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_SPI;
233
234	// reset the SPI
235	pSPI->SPI_CR = AT91C_SPI_SWRST;
236
237	pSPI->SPI_MR = (0xf << 24) | AT91C_SPI_MSTR | AT91C_SPI_MODFDIS |
238	    (0xE << 16);
239
240	pSPI->SPI_CSR[0] = AT91C_SPI_CPOL | (4 << 16) | (2 << 8);
241	pSPI->SPI_CR = AT91C_SPI_SPIEN;
242
243	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS;
244	pSPI->SPI_PTCR = AT91C_PDC_RXTDIS;
245	pSPI->SPI_RNPR = 0;
246	pSPI->SPI_RNCR = 0;
247	pSPI->SPI_TNPR = 0;
248	pSPI->SPI_TNCR = 0;
249	pSPI->SPI_RPR = 0;
250	pSPI->SPI_RCR = 0;
251	pSPI->SPI_TPR = 0;
252	pSPI->SPI_TCR = 0;
253	pSPI->SPI_PTCR = AT91C_PDC_RXTEN;
254	pSPI->SPI_PTCR = AT91C_PDC_TXTEN;
255
256	value = pSPI->SPI_RDR;
257	value = pSPI->SPI_SR;
258
259	value = GetFlashStatus() & 0xFC;
260#ifdef BOOT_BWCT
261	if (value != 0xB4 && value != 0xAC)
262		printf(" Bad SPI status: 0x%x\n", value);
263#else
264	if (value != 0xBC)
265		printf(" Bad SPI status: 0x%x\n", value);
266#endif
267}
268