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