spi_flash.c revision 163533
139297Sfenner/******************************************************************************
239297Sfenner *
339297Sfenner * Filename: spi_flash.c
439297Sfenner *
539297Sfenner * Instantiation of SPI flash control routines supporting AT45DB161B
639297Sfenner *
739297Sfenner * Revision information:
839297Sfenner *
939297Sfenner * 17JAN2005	kb_admin	initial creation
1039297Sfenner *				adapted from external sources
1139297Sfenner *				tested for basic operation only!!!
1239297Sfenner *
1339297Sfenner * BEGIN_KBDD_BLOCK
1439297Sfenner * No warranty, expressed or implied, is included with this software.  It is
1539297Sfenner * provided "AS IS" and no warranty of any kind including statutory or aspects
1639297Sfenner * relating to merchantability or fitness for any purpose is provided.  All
1739297Sfenner * intellectual property rights of others is maintained with the respective
1839297Sfenner * owners.  This software is not copyrighted and is intended for reference
1939297Sfenner * only.
2039297Sfenner * END_BLOCK
2139297Sfenner *
2239297Sfenner * $FreeBSD: head/sys/boot/arm/at91/libat91/spi_flash.c 163533 2006-10-20 09:12:05Z imp $
23127668Sbms *****************************************************************************/
24127668Sbms
2539297Sfenner#include "at91rm9200.h"
2639297Sfenner#include "spi_flash.h"
2756893Sfenner#include "lib.h"
2856893Sfenner
2956893Sfenner/*********************** PRIVATE FUNCTIONS/DATA ******************************/
3056893Sfenner
31127668Sbms
3239297Sfennerstatic spiCommand_t	spi_command;
3339297Sfennerstatic char		tx_commandBuffer[8], rx_commandBuffer[8];
3439297Sfenner
3539297Sfenner/*
3639297Sfenner * .KB_C_FN_DEFINITION_START
3739297Sfenner * void SendCommand(spiCommand_t *pCommand)
3839297Sfenner *  Private function sends 8-bit value to the device and returns the 8-bit
3939297Sfenner * value in response.
4039297Sfenner * .KB_C_FN_DEFINITION_END
4139297Sfenner */
4239297Sfennerstatic void
4339297SfennerSendCommand(spiCommand_t *pCommand)
4439297Sfenner{
45127668Sbms	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
46127668Sbms
47127668Sbms	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
48127668Sbms
49127668Sbms	pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
50127668Sbms	pSPI->SPI_RCR = pCommand->rx_cmd_size;
51127668Sbms	pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
5239297Sfenner	pSPI->SPI_TCR = pCommand->tx_cmd_size;
53127668Sbms
54127668Sbms	pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
5539297Sfenner	pSPI->SPI_TNCR = pCommand->tx_data_size;
56127668Sbms	pSPI->SPI_RNPR = (unsigned)pCommand->rx_data;
57127668Sbms	pSPI->SPI_RNCR = pCommand->rx_data_size;
58127668Sbms
59127668Sbms	pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
60127668Sbms
61127668Sbms	// wait for completion
62127668Sbms	while (!(pSPI->SPI_SR & AT91C_SPI_SPENDRX))
63127668Sbms		Delay(700);
64127668Sbms}
65127668Sbms
66127668Sbms
67127668Sbms/*
68127668Sbms * .KB_C_FN_DEFINITION_START
69127668Sbms * char GetFlashStatus(void)
70127668Sbms *  Private function to return device status.
71127668Sbms * .KB_C_FN_DEFINITION_END
7239297Sfenner */
7339297Sfennerstatic char
7439297SfennerGetFlashStatus(void)
7539297Sfenner{
7639297Sfenner	p_memset((char *)&spi_command, 0, sizeof(spi_command));
7739297Sfenner	p_memset(tx_commandBuffer, 0, 8);
7839297Sfenner	tx_commandBuffer[0] = STATUS_REGISTER_READ;
7939297Sfenner	p_memset(rx_commandBuffer, 0, 8);
8039297Sfenner	spi_command.tx_cmd = tx_commandBuffer;
8139297Sfenner	spi_command.rx_cmd = rx_commandBuffer;
8239297Sfenner	spi_command.rx_cmd_size = 2;
8339297Sfenner	spi_command.tx_cmd_size = 2;
8439297Sfenner	SendCommand(&spi_command);
8539297Sfenner	return (rx_commandBuffer[1]);
8639297Sfenner}
8739297Sfenner
8839297Sfenner/*
8939297Sfenner * .KB_C_FN_DEFINITION_START
9039297Sfenner * void WaitForDeviceReady(void)
9139297Sfenner *  Private function to poll until the device is ready for next operation.
9239297Sfenner * .KB_C_FN_DEFINITION_END
9339297Sfenner */
94static void
95WaitForDeviceReady(void)
96{
97	while (!(GetFlashStatus() & 0x80)) ;
98}
99
100/*************************** GLOBAL FUNCTIONS ********************************/
101
102
103/*
104 * .KB_C_FN_DEFINITION_START
105 * void SPI_ReadFlash(unsigned flash_addr, unsigned dest_addr, unsigned size)
106 *  Global function to read the SPI flash device using the continuous read
107 * array command.
108 * .KB_C_FN_DEFINITION_END
109 */
110void
111SPI_ReadFlash(unsigned flash_addr, char *dest_addr, unsigned size)
112{
113	unsigned	pageAddress, byteAddress;
114
115	// determine page address
116	pageAddress = flash_addr / FLASH_PAGE_SIZE;
117
118	// determine byte address
119	byteAddress = flash_addr % FLASH_PAGE_SIZE;
120
121	p_memset(tx_commandBuffer, 0, 8);
122	tx_commandBuffer[0] = CONTINUOUS_ARRAY_READ_HF;
123	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
124	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
125				((byteAddress >> 8) & 0x7);
126	tx_commandBuffer[3] = byteAddress & 0xFF;
127	spi_command.tx_cmd = tx_commandBuffer;
128	spi_command.tx_cmd_size = 5;
129	spi_command.tx_data_size = size;
130	spi_command.tx_data = dest_addr;
131
132	p_memset(rx_commandBuffer, 0, 8);
133	spi_command.rx_cmd = rx_commandBuffer;
134	spi_command.rx_cmd_size = 5;
135	spi_command.rx_data_size = size;
136	spi_command.rx_data = dest_addr;
137
138	SendCommand(&spi_command);
139}
140
141
142/*
143 * .KB_C_FN_DEFINITION_START
144 * void SPI_WriteFlash(unsigned flash_addr, unsigned src_addr, unsigned size)
145 *  Global function to program the SPI flash device.  Notice the warning
146 * provided in lower-level functions regarding corruption of data in non-
147 * page aligned write operations.
148 * .KB_C_FN_DEFINITION_END
149 */
150void
151SPI_WriteFlash(unsigned flash_addr, char *src_addr, unsigned size)
152{
153	unsigned	pageAddress, byteAddress;
154
155	// determine page address
156	pageAddress = flash_addr / FLASH_PAGE_SIZE;
157
158	// determine byte address
159	byteAddress = flash_addr % FLASH_PAGE_SIZE;
160
161	p_memset(tx_commandBuffer, 0, 8);
162	tx_commandBuffer[0] = PROGRAM_THROUGH_BUFFER;
163	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
164	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
165				((byteAddress >> 8) & 0x7);
166	tx_commandBuffer[3] = (byteAddress & 0xFF);
167
168	p_memset(rx_commandBuffer, 0, 8);
169
170	spi_command.tx_cmd = tx_commandBuffer;
171	spi_command.rx_cmd = rx_commandBuffer;
172	spi_command.rx_cmd_size = 4;
173	spi_command.tx_cmd_size = 4;
174
175	spi_command.tx_data_size = size;
176	spi_command.tx_data = src_addr;
177	spi_command.rx_data_size = size;
178	spi_command.rx_data = src_addr;
179
180	SendCommand(&spi_command);
181
182	WaitForDeviceReady();
183}
184
185/*
186 * .KB_C_FN_DEFINITION_START
187 * void SPI_InitFlash(void)
188 *  Global function to initialize the SPI flash device/accessor functions.
189 * .KB_C_FN_DEFINITION_END
190 */
191void
192SPI_InitFlash(void)
193{
194	AT91PS_PIO	pPio;
195	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
196	unsigned	value;
197
198	// enable CS0, CLK, MOSI, MISO
199	pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
200	pPio->PIO_ASR = AT91C_PA3_NPCS0 | AT91C_PA1_MOSI | AT91C_PA0_MISO |
201	    AT91C_PA2_SPCK;
202	pPio->PIO_PDR = AT91C_PA3_NPCS0 | AT91C_PA1_MOSI | AT91C_PA0_MISO |
203	    AT91C_PA2_SPCK;
204
205	// enable clocks to SPI
206	AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_SPI;
207
208	// reset the SPI
209	pSPI->SPI_CR = AT91C_SPI_SWRST;
210
211	pSPI->SPI_MR = (0xf << 24) | AT91C_SPI_MSTR | AT91C_SPI_MODFDIS |
212	    (0xE << 16);
213
214	pSPI->SPI_CSR[0] = AT91C_SPI_CPOL | (4 << 16) | (2 << 8);
215	pSPI->SPI_CR = AT91C_SPI_SPIEN;
216
217	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS;
218	pSPI->SPI_PTCR = AT91C_PDC_RXTDIS;
219	pSPI->SPI_RNPR = 0;
220	pSPI->SPI_RNCR = 0;
221	pSPI->SPI_TNPR = 0;
222	pSPI->SPI_TNCR = 0;
223	pSPI->SPI_RPR = 0;
224	pSPI->SPI_RCR = 0;
225	pSPI->SPI_TPR = 0;
226	pSPI->SPI_TCR = 0;
227	pSPI->SPI_PTCR = AT91C_PDC_RXTEN;
228	pSPI->SPI_PTCR = AT91C_PDC_TXTEN;
229
230	value = pSPI->SPI_RDR;
231	value = pSPI->SPI_SR;
232
233	// Increment real time counter every SLCK
234	AT91C_BASE_ST->ST_RTMR = 1;
235
236	if (((value = GetFlashStatus()) & 0xFC) != 0xBC)
237		printf(" Bad SPI status: 0x%x\n", value);
238}
239