spi_flash.c revision 174877
11573Srgrimes/******************************************************************************
21573Srgrimes *
31573Srgrimes * Filename: spi_flash.c
41573Srgrimes *
51573Srgrimes * Instantiation of SPI flash control routines supporting AT45DB161B
61573Srgrimes *
71573Srgrimes * Revision information:
81573Srgrimes *
91573Srgrimes * 17JAN2005	kb_admin	initial creation
101573Srgrimes *				adapted from external sources
111573Srgrimes *				tested for basic operation only!!!
121573Srgrimes *
131573Srgrimes * BEGIN_KBDD_BLOCK
141573Srgrimes * No warranty, expressed or implied, is included with this software.  It is
151573Srgrimes * provided "AS IS" and no warranty of any kind including statutory or aspects
16249808Semaste * relating to merchantability or fitness for any purpose is provided.  All
171573Srgrimes * intellectual property rights of others is maintained with the respective
181573Srgrimes * owners.  This software is not copyrighted and is intended for reference
191573Srgrimes * only.
201573Srgrimes * END_BLOCK
211573Srgrimes *
221573Srgrimes * $FreeBSD: head/sys/boot/arm/at91/libat91/spi_flash.c 174877 2007-12-23 14:46:30Z ticso $
231573Srgrimes *****************************************************************************/
241573Srgrimes
251573Srgrimes#include "at91rm9200.h"
261573Srgrimes#include "spi_flash.h"
271573Srgrimes#include "lib.h"
281573Srgrimes
291573Srgrimes/*********************** PRIVATE FUNCTIONS/DATA ******************************/
301573Srgrimes
311573Srgrimes
321573Srgrimesstatic spiCommand_t	spi_command;
331573Srgrimesstatic char		tx_commandBuffer[8], rx_commandBuffer[8];
341573Srgrimes
351573Srgrimes/*
3692986Sobrien * .KB_C_FN_DEFINITION_START
3792986Sobrien * void SendCommand(spiCommand_t *pCommand)
381573Srgrimes *  Private function sends 8-bit value to the device and returns the 8-bit
391573Srgrimes * value in response.
401573Srgrimes * .KB_C_FN_DEFINITION_END
411573Srgrimes */
42249810Semastestatic void
431573SrgrimesSendCommand(spiCommand_t *pCommand)
441573Srgrimes{
4516586Sjraynard	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
461573Srgrimes
471573Srgrimes	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
481573Srgrimes
491573Srgrimes	pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
501573Srgrimes	pSPI->SPI_RCR = pCommand->rx_cmd_size;
511573Srgrimes	pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
52249810Semaste	pSPI->SPI_TCR = pCommand->tx_cmd_size;
531573Srgrimes
541573Srgrimes	pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
551573Srgrimes	pSPI->SPI_TNCR = pCommand->tx_data_size;
561573Srgrimes	pSPI->SPI_RNPR = (unsigned)pCommand->rx_data;
57	pSPI->SPI_RNCR = pCommand->rx_data_size;
58
59	pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
60
61	// wait for completion
62	while (!(pSPI->SPI_SR & AT91C_SPI_SPENDRX))
63		Delay(700);
64}
65
66
67/*
68 * .KB_C_FN_DEFINITION_START
69 * char GetFlashStatus(void)
70 *  Private function to return device status.
71 * .KB_C_FN_DEFINITION_END
72 */
73static char
74GetFlashStatus(void)
75{
76	p_memset((char *)&spi_command, 0, sizeof(spi_command));
77	p_memset(tx_commandBuffer, 0, 8);
78	tx_commandBuffer[0] = STATUS_REGISTER_READ;
79	p_memset(rx_commandBuffer, 0, 8);
80	spi_command.tx_cmd = tx_commandBuffer;
81	spi_command.rx_cmd = rx_commandBuffer;
82	spi_command.rx_cmd_size = 2;
83	spi_command.tx_cmd_size = 2;
84	SendCommand(&spi_command);
85	return (rx_commandBuffer[1]);
86}
87
88/*
89 * .KB_C_FN_DEFINITION_START
90 * void WaitForDeviceReady(void)
91 *  Private function to poll until the device is ready for next operation.
92 * .KB_C_FN_DEFINITION_END
93 */
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#ifdef BOOT_BWCT
123	tx_commandBuffer[0] = 0xd2;
124	tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
125	tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
126				((byteAddress >> 8) & 0x3);
127	tx_commandBuffer[3] = byteAddress & 0xFF;
128	spi_command.tx_cmd = tx_commandBuffer;
129	spi_command.tx_cmd_size = 8;
130	spi_command.tx_data_size = size;
131	spi_command.tx_data = dest_addr;
132
133	p_memset(rx_commandBuffer, 0, 8);
134	spi_command.rx_cmd = rx_commandBuffer;
135	spi_command.rx_cmd_size = 8;
136	spi_command.rx_data_size = size;
137	spi_command.rx_data = dest_addr;
138#else
139	tx_commandBuffer[0] = CONTINUOUS_ARRAY_READ_HF;
140	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
141	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
142				((byteAddress >> 8) & 0x7);
143	tx_commandBuffer[3] = byteAddress & 0xFF;
144	spi_command.tx_cmd = tx_commandBuffer;
145	spi_command.tx_cmd_size = 5;
146	spi_command.tx_data_size = size;
147	spi_command.tx_data = dest_addr;
148
149	p_memset(rx_commandBuffer, 0, 8);
150	spi_command.rx_cmd = rx_commandBuffer;
151	spi_command.rx_cmd_size = 5;
152	spi_command.rx_data_size = size;
153	spi_command.rx_data = dest_addr;
154#endif
155
156	SendCommand(&spi_command);
157}
158
159
160/*
161 * .KB_C_FN_DEFINITION_START
162 * void SPI_WriteFlash(unsigned flash_addr, unsigned src_addr, unsigned size)
163 *  Global function to program the SPI flash device.  Notice the warning
164 * provided in lower-level functions regarding corruption of data in non-
165 * page aligned write operations.
166 * .KB_C_FN_DEFINITION_END
167 */
168void
169SPI_WriteFlash(unsigned flash_addr, char *src_addr, unsigned size)
170{
171	unsigned	pageAddress, byteAddress;
172
173	// determine page address
174	pageAddress = flash_addr / FLASH_PAGE_SIZE;
175
176	// determine byte address
177	byteAddress = flash_addr % FLASH_PAGE_SIZE;
178
179	p_memset(tx_commandBuffer, 0, 8);
180#ifdef BOOT_BWCT
181	tx_commandBuffer[0] = 0x82;
182	tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
183	tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
184				((byteAddress >> 8) & 0x3);
185	tx_commandBuffer[3] = (byteAddress & 0xFF);
186#else
187	tx_commandBuffer[0] = PROGRAM_THROUGH_BUFFER;
188	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
189	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
190				((byteAddress >> 8) & 0x7);
191	tx_commandBuffer[3] = (byteAddress & 0xFF);
192#endif
193
194	p_memset(rx_commandBuffer, 0, 8);
195
196	spi_command.tx_cmd = tx_commandBuffer;
197	spi_command.rx_cmd = rx_commandBuffer;
198	spi_command.rx_cmd_size = 4;
199	spi_command.tx_cmd_size = 4;
200
201	spi_command.tx_data_size = size;
202	spi_command.tx_data = src_addr;
203	spi_command.rx_data_size = size;
204	spi_command.rx_data = src_addr;
205
206	SendCommand(&spi_command);
207
208	WaitForDeviceReady();
209}
210
211/*
212 * .KB_C_FN_DEFINITION_START
213 * void SPI_InitFlash(void)
214 *  Global function to initialize the SPI flash device/accessor functions.
215 * .KB_C_FN_DEFINITION_END
216 */
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