1 /******************************************************************************
2 *
3 * Filename: spi_flash.c
4 *
5 * Instantiation of SPI flash control routines supporting AT45DB161B
6 *
7 * Revision information:
8 *
9 * 17JAN2005 kb_admin initial creation
10 * adapted from external sources
11 * tested for basic operation only!!!
12 *
13 * BEGIN_KBDD_BLOCK
14 * No warranty, expressed or implied, is included with this software. It is
15 * provided "AS IS" and no warranty of any kind including statutory or aspects
16 * relating to merchantability or fitness for any purpose is provided. All
17 * intellectual property rights of others is maintained with the respective
18 * owners. This software is not copyrighted and is intended for reference
19 * only.
20 * END_BLOCK
21 *
22 * $FreeBSD$
23 *****************************************************************************/
24
25 #include "at91rm9200.h"
26 #include "spi_flash.h"
27 #include "lib.h"
28
29 /*********************** PRIVATE FUNCTIONS/DATA ******************************/
30
31
32 static spiCommand_t spi_command;
33 static char tx_commandBuffer[8], rx_commandBuffer[8];
34
35 /*
36 * .KB_C_FN_DEFINITION_START
37 * void SendCommand(spiCommand_t *pCommand)
38 * Private function sends 8-bit value to the device and returns the 8-bit
39 * value in response.
40 * .KB_C_FN_DEFINITION_END
41 */
42 static void
SendCommand(spiCommand_t * pCommand)43 SendCommand(spiCommand_t *pCommand)
44 {
45 AT91PS_SPI pSPI = AT91C_BASE_SPI;
46
47 pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
48
49 pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
50 pSPI->SPI_RCR = pCommand->rx_cmd_size;
51 pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
52 pSPI->SPI_TCR = pCommand->tx_cmd_size;
53
54 pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
55 pSPI->SPI_TNCR = pCommand->tx_data_size;
56 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 */
73 static char
GetFlashStatus(void)74 GetFlashStatus(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 */
94 static void
WaitForDeviceReady(void)95 WaitForDeviceReady(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 */
110 void
SPI_ReadFlash(unsigned flash_addr,char * dest_addr,unsigned size)111 SPI_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 */
168 void
SPI_WriteFlash(unsigned flash_addr,char * src_addr,unsigned size)169 SPI_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 */
217 void
SPI_InitFlash(void)218 SPI_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_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
227 AT91C_PIO_PA2;
228 pPio->PIO_PDR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
229 AT91C_PIO_PA2;
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