1161197Simp/******************************************************************************
2161197Simp *
3161197Simp * Filename: spi_flash.c
4161197Simp *
5161197Simp * Instantiation of SPI flash control routines supporting AT45DB161B
6161197Simp *
7161197Simp * Revision information:
8161197Simp *
9161197Simp * 17JAN2005	kb_admin	initial creation
10161197Simp *				adapted from external sources
11161197Simp *				tested for basic operation only!!!
12161197Simp *
13161197Simp * BEGIN_KBDD_BLOCK
14161197Simp * No warranty, expressed or implied, is included with this software.  It is
15161197Simp * provided "AS IS" and no warranty of any kind including statutory or aspects
16161197Simp * relating to merchantability or fitness for any purpose is provided.  All
17161197Simp * intellectual property rights of others is maintained with the respective
18161197Simp * owners.  This software is not copyrighted and is intended for reference
19161197Simp * only.
20161197Simp * END_BLOCK
21161197Simp *
22161197Simp * $FreeBSD$
23161197Simp *****************************************************************************/
24161197Simp
25161197Simp#include "at91rm9200.h"
26161197Simp#include "spi_flash.h"
27161197Simp#include "lib.h"
28161197Simp
29161197Simp/*********************** PRIVATE FUNCTIONS/DATA ******************************/
30161197Simp
31161197Simp
32161197Simpstatic spiCommand_t	spi_command;
33161197Simpstatic char		tx_commandBuffer[8], rx_commandBuffer[8];
34161197Simp
35161197Simp/*
36161197Simp * .KB_C_FN_DEFINITION_START
37161197Simp * void SendCommand(spiCommand_t *pCommand)
38161197Simp *  Private function sends 8-bit value to the device and returns the 8-bit
39161197Simp * value in response.
40161197Simp * .KB_C_FN_DEFINITION_END
41161197Simp */
42161197Simpstatic void
43161197SimpSendCommand(spiCommand_t *pCommand)
44161197Simp{
45161197Simp	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
46161197Simp
47161197Simp	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
48161197Simp
49161197Simp	pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
50161197Simp	pSPI->SPI_RCR = pCommand->rx_cmd_size;
51161197Simp	pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
52161197Simp	pSPI->SPI_TCR = pCommand->tx_cmd_size;
53161197Simp
54161197Simp	pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
55161197Simp	pSPI->SPI_TNCR = pCommand->tx_data_size;
56161197Simp	pSPI->SPI_RNPR = (unsigned)pCommand->rx_data;
57161197Simp	pSPI->SPI_RNCR = pCommand->rx_data_size;
58161197Simp
59161197Simp	pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
60161197Simp
61161197Simp	// wait for completion
62161197Simp	while (!(pSPI->SPI_SR & AT91C_SPI_SPENDRX))
63161197Simp		Delay(700);
64161197Simp}
65161197Simp
66161197Simp
67161197Simp/*
68161197Simp * .KB_C_FN_DEFINITION_START
69161197Simp * char GetFlashStatus(void)
70161197Simp *  Private function to return device status.
71161197Simp * .KB_C_FN_DEFINITION_END
72161197Simp */
73161197Simpstatic char
74161197SimpGetFlashStatus(void)
75161197Simp{
76161197Simp	p_memset((char *)&spi_command, 0, sizeof(spi_command));
77161197Simp	p_memset(tx_commandBuffer, 0, 8);
78161197Simp	tx_commandBuffer[0] = STATUS_REGISTER_READ;
79161197Simp	p_memset(rx_commandBuffer, 0, 8);
80161197Simp	spi_command.tx_cmd = tx_commandBuffer;
81161197Simp	spi_command.rx_cmd = rx_commandBuffer;
82161197Simp	spi_command.rx_cmd_size = 2;
83161197Simp	spi_command.tx_cmd_size = 2;
84161197Simp	SendCommand(&spi_command);
85161197Simp	return (rx_commandBuffer[1]);
86161197Simp}
87161197Simp
88161197Simp/*
89161197Simp * .KB_C_FN_DEFINITION_START
90161197Simp * void WaitForDeviceReady(void)
91161197Simp *  Private function to poll until the device is ready for next operation.
92161197Simp * .KB_C_FN_DEFINITION_END
93161197Simp */
94161197Simpstatic void
95161197SimpWaitForDeviceReady(void)
96161197Simp{
97161197Simp	while (!(GetFlashStatus() & 0x80)) ;
98161197Simp}
99161197Simp
100161197Simp/*************************** GLOBAL FUNCTIONS ********************************/
101161197Simp
102161197Simp
103161197Simp/*
104161197Simp * .KB_C_FN_DEFINITION_START
105161197Simp * void SPI_ReadFlash(unsigned flash_addr, unsigned dest_addr, unsigned size)
106161197Simp *  Global function to read the SPI flash device using the continuous read
107161197Simp * array command.
108161197Simp * .KB_C_FN_DEFINITION_END
109161197Simp */
110161197Simpvoid
111161197SimpSPI_ReadFlash(unsigned flash_addr, char *dest_addr, unsigned size)
112161197Simp{
113161197Simp	unsigned	pageAddress, byteAddress;
114161197Simp
115161197Simp	// determine page address
116161197Simp	pageAddress = flash_addr / FLASH_PAGE_SIZE;
117161197Simp
118161197Simp	// determine byte address
119161197Simp	byteAddress = flash_addr % FLASH_PAGE_SIZE;
120161197Simp
121161197Simp	p_memset(tx_commandBuffer, 0, 8);
122165400Simp#ifdef BOOT_BWCT
123165400Simp	tx_commandBuffer[0] = 0xd2;
124165400Simp	tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
125165400Simp	tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
126165400Simp				((byteAddress >> 8) & 0x3);
127165400Simp	tx_commandBuffer[3] = byteAddress & 0xFF;
128165400Simp	spi_command.tx_cmd = tx_commandBuffer;
129165400Simp	spi_command.tx_cmd_size = 8;
130165400Simp	spi_command.tx_data_size = size;
131165400Simp	spi_command.tx_data = dest_addr;
132165400Simp
133165400Simp	p_memset(rx_commandBuffer, 0, 8);
134165400Simp	spi_command.rx_cmd = rx_commandBuffer;
135165400Simp	spi_command.rx_cmd_size = 8;
136165400Simp	spi_command.rx_data_size = size;
137165400Simp	spi_command.rx_data = dest_addr;
138165400Simp#else
139161197Simp	tx_commandBuffer[0] = CONTINUOUS_ARRAY_READ_HF;
140161197Simp	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
141161197Simp	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
142161197Simp				((byteAddress >> 8) & 0x7);
143161197Simp	tx_commandBuffer[3] = byteAddress & 0xFF;
144161197Simp	spi_command.tx_cmd = tx_commandBuffer;
145161197Simp	spi_command.tx_cmd_size = 5;
146161197Simp	spi_command.tx_data_size = size;
147161197Simp	spi_command.tx_data = dest_addr;
148161197Simp
149161197Simp	p_memset(rx_commandBuffer, 0, 8);
150161197Simp	spi_command.rx_cmd = rx_commandBuffer;
151161197Simp	spi_command.rx_cmd_size = 5;
152161197Simp	spi_command.rx_data_size = size;
153161197Simp	spi_command.rx_data = dest_addr;
154165400Simp#endif
155161197Simp
156161197Simp	SendCommand(&spi_command);
157161197Simp}
158161197Simp
159161197Simp
160161197Simp/*
161161197Simp * .KB_C_FN_DEFINITION_START
162161197Simp * void SPI_WriteFlash(unsigned flash_addr, unsigned src_addr, unsigned size)
163161197Simp *  Global function to program the SPI flash device.  Notice the warning
164161197Simp * provided in lower-level functions regarding corruption of data in non-
165161197Simp * page aligned write operations.
166161197Simp * .KB_C_FN_DEFINITION_END
167161197Simp */
168161197Simpvoid
169161197SimpSPI_WriteFlash(unsigned flash_addr, char *src_addr, unsigned size)
170161197Simp{
171161197Simp	unsigned	pageAddress, byteAddress;
172161197Simp
173161197Simp	// determine page address
174161197Simp	pageAddress = flash_addr / FLASH_PAGE_SIZE;
175161197Simp
176161197Simp	// determine byte address
177161197Simp	byteAddress = flash_addr % FLASH_PAGE_SIZE;
178161197Simp
179161197Simp	p_memset(tx_commandBuffer, 0, 8);
180165400Simp#ifdef BOOT_BWCT
181165400Simp	tx_commandBuffer[0] = 0x82;
182165400Simp	tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
183165400Simp	tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
184165400Simp				((byteAddress >> 8) & 0x3);
185165400Simp	tx_commandBuffer[3] = (byteAddress & 0xFF);
186165400Simp#else
187161197Simp	tx_commandBuffer[0] = PROGRAM_THROUGH_BUFFER;
188161197Simp	tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
189161197Simp	tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
190161197Simp				((byteAddress >> 8) & 0x7);
191161197Simp	tx_commandBuffer[3] = (byteAddress & 0xFF);
192165400Simp#endif
193161197Simp
194161197Simp	p_memset(rx_commandBuffer, 0, 8);
195161197Simp
196161197Simp	spi_command.tx_cmd = tx_commandBuffer;
197161197Simp	spi_command.rx_cmd = rx_commandBuffer;
198161197Simp	spi_command.rx_cmd_size = 4;
199161197Simp	spi_command.tx_cmd_size = 4;
200161197Simp
201161197Simp	spi_command.tx_data_size = size;
202161197Simp	spi_command.tx_data = src_addr;
203161197Simp	spi_command.rx_data_size = size;
204161197Simp	spi_command.rx_data = src_addr;
205161197Simp
206161197Simp	SendCommand(&spi_command);
207161197Simp
208161197Simp	WaitForDeviceReady();
209161197Simp}
210161197Simp
211161197Simp/*
212161197Simp * .KB_C_FN_DEFINITION_START
213161197Simp * void SPI_InitFlash(void)
214161197Simp *  Global function to initialize the SPI flash device/accessor functions.
215161197Simp * .KB_C_FN_DEFINITION_END
216161197Simp */
217161197Simpvoid
218161197SimpSPI_InitFlash(void)
219161197Simp{
220161197Simp	AT91PS_PIO	pPio;
221161197Simp	AT91PS_SPI	pSPI = AT91C_BASE_SPI;
222161197Simp	unsigned	value;
223161197Simp
224161197Simp	// enable CS0, CLK, MOSI, MISO
225161197Simp	pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
226238463Simp	pPio->PIO_ASR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
227238463Simp	    AT91C_PIO_PA2;
228238463Simp	pPio->PIO_PDR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
229238463Simp	    AT91C_PIO_PA2;
230161197Simp
231161197Simp	// enable clocks to SPI
232161197Simp	AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_SPI;
233161197Simp
234161197Simp	// reset the SPI
235161197Simp	pSPI->SPI_CR = AT91C_SPI_SWRST;
236161197Simp
237161197Simp	pSPI->SPI_MR = (0xf << 24) | AT91C_SPI_MSTR | AT91C_SPI_MODFDIS |
238161197Simp	    (0xE << 16);
239161197Simp
240161197Simp	pSPI->SPI_CSR[0] = AT91C_SPI_CPOL | (4 << 16) | (2 << 8);
241161197Simp	pSPI->SPI_CR = AT91C_SPI_SPIEN;
242161197Simp
243161197Simp	pSPI->SPI_PTCR = AT91C_PDC_TXTDIS;
244161197Simp	pSPI->SPI_PTCR = AT91C_PDC_RXTDIS;
245161197Simp	pSPI->SPI_RNPR = 0;
246161197Simp	pSPI->SPI_RNCR = 0;
247161197Simp	pSPI->SPI_TNPR = 0;
248161197Simp	pSPI->SPI_TNCR = 0;
249161197Simp	pSPI->SPI_RPR = 0;
250161197Simp	pSPI->SPI_RCR = 0;
251161197Simp	pSPI->SPI_TPR = 0;
252161197Simp	pSPI->SPI_TCR = 0;
253161197Simp	pSPI->SPI_PTCR = AT91C_PDC_RXTEN;
254161197Simp	pSPI->SPI_PTCR = AT91C_PDC_TXTEN;
255161197Simp
256161197Simp	value = pSPI->SPI_RDR;
257161197Simp	value = pSPI->SPI_SR;
258161197Simp
259174877Sticso	value = GetFlashStatus() & 0xFC;
260165400Simp#ifdef BOOT_BWCT
261174877Sticso	if (value != 0xB4 && value != 0xAC)
262165400Simp		printf(" Bad SPI status: 0x%x\n", value);
263165400Simp#else
264174877Sticso	if (value != 0xBC)
265163533Simp		printf(" Bad SPI status: 0x%x\n", value);
266165400Simp#endif
267161197Simp}
268