spi_flash.c revision 163533
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: head/sys/boot/arm/at91/libat91/spi_flash.c 163533 2006-10-20 09:12:05Z imp $ 23 *****************************************************************************/ 24 25#include "at91rm9200.h" 26#include "spi_flash.h" 27#include "lib.h" 28 29/*********************** PRIVATE FUNCTIONS/DATA ******************************/ 30 31 32static spiCommand_t spi_command; 33static 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 */ 42static void 43SendCommand(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 */ 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 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