spi_flash.c revision 174877
175584Sru/****************************************************************************** 275584Sru * 375584Sru * Filename: spi_flash.c 4104862Sru * 575584Sru * Instantiation of SPI flash control routines supporting AT45DB161B 675584Sru * 775584Sru * Revision information: 875584Sru * 975584Sru * 17JAN2005 kb_admin initial creation 1075584Sru * adapted from external sources 1175584Sru * tested for basic operation only!!! 1275584Sru * 1375584Sru * BEGIN_KBDD_BLOCK 1475584Sru * No warranty, expressed or implied, is included with this software. It is 15104862Sru * provided "AS IS" and no warranty of any kind including statutory or aspects 1675584Sru * relating to merchantability or fitness for any purpose is provided. All 1775584Sru * intellectual property rights of others is maintained with the respective 1875584Sru * owners. This software is not copyrighted and is intended for reference 1975584Sru * only. 2075584Sru * END_BLOCK 2175584Sru * 22104862Sru * $FreeBSD: head/sys/boot/arm/at91/libat91/spi_flash.c 174877 2007-12-23 14:46:30Z ticso $ 2375584Sru *****************************************************************************/ 2475584Sru 2575584Sru#include "at91rm9200.h" 26104862Sru#include "spi_flash.h" 2775584Sru#include "lib.h" 28104862Sru 2975584Sru/*********************** PRIVATE FUNCTIONS/DATA ******************************/ 3075584Sru 3175584Sru 3275584Srustatic spiCommand_t spi_command; 3375584Srustatic char tx_commandBuffer[8], rx_commandBuffer[8]; 3475584Sru 3575584Sru/* 3675584Sru * .KB_C_FN_DEFINITION_START 3775584Sru * void SendCommand(spiCommand_t *pCommand) 3875584Sru * Private function sends 8-bit value to the device and returns the 8-bit 3975584Sru * value in response. 4075584Sru * .KB_C_FN_DEFINITION_END 4175584Sru */ 4275584Srustatic void 4375584SruSendCommand(spiCommand_t *pCommand) 4475584Sru{ 4575584Sru AT91PS_SPI pSPI = AT91C_BASE_SPI; 4675584Sru 4775584Sru pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS; 4875584Sru 4975584Sru pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd; 5075584Sru pSPI->SPI_RCR = pCommand->rx_cmd_size; 5175584Sru pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd; 5275584Sru pSPI->SPI_TCR = pCommand->tx_cmd_size; 5375584Sru 5475584Sru pSPI->SPI_TNPR = (unsigned)pCommand->tx_data; 5575584Sru pSPI->SPI_TNCR = pCommand->tx_data_size; 5675584Sru pSPI->SPI_RNPR = (unsigned)pCommand->rx_data; 5775584Sru pSPI->SPI_RNCR = pCommand->rx_data_size; 5875584Sru 5975584Sru pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN; 6075584Sru 6175584Sru // wait for completion 6275584Sru while (!(pSPI->SPI_SR & AT91C_SPI_SPENDRX)) 6375584Sru Delay(700); 6475584Sru} 6575584Sru 6675584Sru 6775584Sru/* 6875584Sru * .KB_C_FN_DEFINITION_START 6975584Sru * char GetFlashStatus(void) 7075584Sru * Private function to return device status. 7175584Sru * .KB_C_FN_DEFINITION_END 7275584Sru */ 7375584Srustatic char 7475584SruGetFlashStatus(void) 7575584Sru{ 7675584Sru p_memset((char *)&spi_command, 0, sizeof(spi_command)); 7775584Sru p_memset(tx_commandBuffer, 0, 8); 7875584Sru tx_commandBuffer[0] = STATUS_REGISTER_READ; 7975584Sru p_memset(rx_commandBuffer, 0, 8); 8075584Sru spi_command.tx_cmd = tx_commandBuffer; 81104862Sru spi_command.rx_cmd = rx_commandBuffer; 8275584Sru spi_command.rx_cmd_size = 2; 8375584Sru spi_command.tx_cmd_size = 2; 8475584Sru SendCommand(&spi_command); 8575584Sru return (rx_commandBuffer[1]); 8675584Sru} 8775584Sru 8875584Sru/* 8975584Sru * .KB_C_FN_DEFINITION_START 9075584Sru * void WaitForDeviceReady(void) 9175584Sru * Private function to poll until the device is ready for next operation. 9275584Sru * .KB_C_FN_DEFINITION_END 9375584Sru */ 9475584Srustatic void 9575584SruWaitForDeviceReady(void) 9675584Sru{ 9775584Sru while (!(GetFlashStatus() & 0x80)) ; 9875584Sru} 9975584Sru 10075584Sru/*************************** GLOBAL FUNCTIONS ********************************/ 10175584Sru 10275584Sru 10375584Sru/* 10475584Sru * .KB_C_FN_DEFINITION_START 10575584Sru * void SPI_ReadFlash(unsigned flash_addr, unsigned dest_addr, unsigned size) 10675584Sru * Global function to read the SPI flash device using the continuous read 10775584Sru * array command. 10875584Sru * .KB_C_FN_DEFINITION_END 10975584Sru */ 11075584Sruvoid 11175584SruSPI_ReadFlash(unsigned flash_addr, char *dest_addr, unsigned size) 11275584Sru{ 11375584Sru unsigned pageAddress, byteAddress; 11475584Sru 11575584Sru // determine page address 11675584Sru pageAddress = flash_addr / FLASH_PAGE_SIZE; 11775584Sru 11875584Sru // determine byte address 11975584Sru byteAddress = flash_addr % FLASH_PAGE_SIZE; 120104862Sru 12175584Sru p_memset(tx_commandBuffer, 0, 8); 12275584Sru#ifdef BOOT_BWCT 12375584Sru tx_commandBuffer[0] = 0xd2; 12475584Sru tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF); 12575584Sru tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) | 12675584Sru ((byteAddress >> 8) & 0x3); 12775584Sru tx_commandBuffer[3] = byteAddress & 0xFF; 12875584Sru spi_command.tx_cmd = tx_commandBuffer; 12975584Sru spi_command.tx_cmd_size = 8; 13075584Sru spi_command.tx_data_size = size; 13175584Sru spi_command.tx_data = dest_addr; 13275584Sru 13375584Sru p_memset(rx_commandBuffer, 0, 8); 13475584Sru spi_command.rx_cmd = rx_commandBuffer; 13575584Sru spi_command.rx_cmd_size = 8; 13675584Sru spi_command.rx_data_size = size; 13775584Sru spi_command.rx_data = dest_addr; 138104862Sru#else 13975584Sru tx_commandBuffer[0] = CONTINUOUS_ARRAY_READ_HF; 14075584Sru tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF); 14175584Sru tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) | 142104862Sru ((byteAddress >> 8) & 0x7); 14375584Sru tx_commandBuffer[3] = byteAddress & 0xFF; 14475584Sru spi_command.tx_cmd = tx_commandBuffer; 14575584Sru spi_command.tx_cmd_size = 5; 14675584Sru spi_command.tx_data_size = size; 14775584Sru spi_command.tx_data = dest_addr; 14875584Sru 14975584Sru p_memset(rx_commandBuffer, 0, 8); 15075584Sru spi_command.rx_cmd = rx_commandBuffer; 15175584Sru spi_command.rx_cmd_size = 5; 15275584Sru spi_command.rx_data_size = size; 15375584Sru spi_command.rx_data = dest_addr; 15475584Sru#endif 15575584Sru 15675584Sru SendCommand(&spi_command); 15775584Sru} 15875584Sru 15975584Sru 16075584Sru/* 16175584Sru * .KB_C_FN_DEFINITION_START 16275584Sru * void SPI_WriteFlash(unsigned flash_addr, unsigned src_addr, unsigned size) 16375584Sru * Global function to program the SPI flash device. Notice the warning 16475584Sru * provided in lower-level functions regarding corruption of data in non- 16575584Sru * page aligned write operations. 16675584Sru * .KB_C_FN_DEFINITION_END 16775584Sru */ 16875584Sruvoid 16975584SruSPI_WriteFlash(unsigned flash_addr, char *src_addr, unsigned size) 17075584Sru{ 17175584Sru unsigned pageAddress, byteAddress; 17275584Sru 17375584Sru // determine page address 17475584Sru pageAddress = flash_addr / FLASH_PAGE_SIZE; 17575584Sru 176104862Sru // determine byte address 17775584Sru byteAddress = flash_addr % FLASH_PAGE_SIZE; 17875584Sru 17975584Sru p_memset(tx_commandBuffer, 0, 8); 18075584Sru#ifdef BOOT_BWCT 18175584Sru tx_commandBuffer[0] = 0x82; 18275584Sru tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF); 18375584Sru tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) | 18475584Sru ((byteAddress >> 8) & 0x3); 18575584Sru tx_commandBuffer[3] = (byteAddress & 0xFF); 18675584Sru#else 18775584Sru tx_commandBuffer[0] = PROGRAM_THROUGH_BUFFER; 18875584Sru tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF); 18975584Sru tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) | 19075584Sru ((byteAddress >> 8) & 0x7); 19175584Sru tx_commandBuffer[3] = (byteAddress & 0xFF); 19275584Sru#endif 19375584Sru 19475584Sru p_memset(rx_commandBuffer, 0, 8); 19575584Sru 19675584Sru spi_command.tx_cmd = tx_commandBuffer; 19775584Sru spi_command.rx_cmd = rx_commandBuffer; 19875584Sru spi_command.rx_cmd_size = 4; 19975584Sru spi_command.tx_cmd_size = 4; 20075584Sru 20175584Sru spi_command.tx_data_size = size; 20275584Sru spi_command.tx_data = src_addr; 20375584Sru spi_command.rx_data_size = size; 20475584Sru spi_command.rx_data = src_addr; 20575584Sru 20675584Sru SendCommand(&spi_command); 20775584Sru 208104862Sru WaitForDeviceReady(); 20975584Sru} 21075584Sru 21175584Sru/* 21275584Sru * .KB_C_FN_DEFINITION_START 21375584Sru * void SPI_InitFlash(void) 21475584Sru * Global function to initialize the SPI flash device/accessor functions. 21575584Sru * .KB_C_FN_DEFINITION_END 21675584Sru */ 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