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 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 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 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 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 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 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