/* * board/arizona/flash_spi.c * * Copyright (C) 2009 SPiDCOM Technologies * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Author(s): * Drasko DRASKOVIC, drasko.draskovic@spidcom.com */ #include #include #include //#define DEBUG_FLASH_SPI DECLARE_GLOBAL_DATA_PTR; /* Flash Organization Structure */ typedef struct OrgDef { unsigned int sector_number; unsigned int sector_size; } OrgDef; extern flash_info_t flash_info[]; /* info for SPI FLASH chip */ /* OPCODES (all one byte long for Spansion S25FL064A SPI Flash */ /* write */ #define READ (unsigned char)(0x03) /* Read Data Bytes */ #define FAST_READ (unsigned char)(0x0B) /* Read Data Bytes at Higher Speed */ #define RDID (unsigned char)(0x9F) /* Read Identification */ /* write */ #define WREN (unsigned char)(0x06) /* Write Enable */ #define WRDI (unsigned char)(0x04) /* Write Disable */ /* erase */ #define SE (unsigned char)(0xD8) /* Sector Erase */ #define BE (unsigned char)(0xC7) /* Bulk (Chip) Erase */ /* program */ #define PP (unsigned char)(0x02) /* Page Program */ /* Status Register */ #define RDSR (unsigned char)(0x05) /* Read from Status Register */ #define WRSR (unsigned char)(0x01) /* Write to Status Register */ /* Status Register bits. */ #define SR_WIP 0x01 /* Write in progress */ #define SR_WEL 0x02 /* Write enable latch */ #define SR_BP0 0x04 /* Block protect 0 */ #define SR_BP1 0x08 /* Block protect 1 */ #define SR_BP2 0x10 /* Block protect 2 */ #define SR_SRWD 0x80 /* SR write protect */ /* SPC300 SPI Controller registers */ #define SPI_CTL_MASTER_SLAVE_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x00) ) ) #define SPI_CTL_CONTROL_CONFIG_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x04) ) ) #define SPI_CTL_FREQ_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x08) ) ) #define SPI_CTL_CONF_TX ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x10) ) ) #define SPI_CTL_CONF_RX ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x14) ) ) #define SPI_CTL_CS_LATENCY ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x18) ) ) #define SPI_CTL_TX_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x20) ) ) #define SPI_CTL_RX_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x24) ) ) #define SPI_CTL_MASK_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x34) ) ) #define SPI_CTL_STATUS_REG ( *( (volatile unsigned int *)(CFG_FLASH_SPI_BASE + 0x38) ) ) /* status bits */ enum { EMPTY_FIFO_TX = 0x01, FULL_FIFO_TX = 0x02, EMPTY_FIFO_RX = 0x04, FULL_FIFO_RX = 0x08, RECEIVED_WORD = 0x10, BUSY_MASTER = 0x20 }; #define READY_SPI 0x00000001 #define ERR_SPI 0x00000002 #define TMO_SPI 0x00000004 int ERROR_FLASH_SPI = 0; int flash_read_status_spi(unsigned char *flash_spi_status); int flash_read_id_spi(unsigned int *flash_spi_id); void swap_endians (int *in) { *in = ( ( (*in & 0xFF000000) >> 24 ) | ( (*in & 0x00FF0000) >> 8 ) | ( (*in & 0x0000FF00) << 8 ) | ( (*in & 0x000000FF) << 24 ) ); } void seterr_flash_spi(int val) { ERROR_FLASH_SPI = val; } /** * Function: init_spi_controller * Parameters: * Purpose: Initialize SPI controller to use SPI flash * Return Value: ushort */ void init_spi_controller(void) { //printf("Initializing SPI controller...\n"); SPI_CTL_MASTER_SLAVE_REG = 0x01; /* Master */ SPI_CTL_CONTROL_CONFIG_REG = 0x00; /* 3 wires Master */ SPI_CTL_FREQ_REG = 0x00; /* 12.5 Mhz (MARIA_MASTER_CLOCK/2) */ SPI_CTL_CS_LATENCY = 0x20; /* 32 cycle clock AHB */ SPI_CTL_CONF_TX = 0x00010008; /* send one byte (i.e. one word of lenght of 8 bits) */ SPI_CTL_CONF_RX = 0x00010008; /* receive one byte */ SPI_CTL_MASK_REG = 0x0; /* mask all interrupts */ } /** * Function: flash_read_id_spi * Parameters: none * Purpose: Read flash id * Return Value: int */ int flash_read_id_spi(unsigned int *flash_spi_id) { int rc = ERR_OK; unsigned long nowtime; /* do not reset timer, because this function might be called from another which already checks timer. This would clobber the result for the caller. Rather use delta time */ nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO ) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* read spi flash status reg */ SPI_CTL_CONF_TX = 0x00010008; /* send one byte */ SPI_CTL_CONF_RX = 0x00010018; /* receive 3 bytes */ /*issue the command to spi flash */ SPI_CTL_TX_REG = RDID; /* busy wait for RECEIVED_WORD bit in status reg */ nowtime = get_timer(0); while ( (SPI_CTL_STATUS_REG & RECEIVED_WORD) == 0 ) { /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO ) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ /* flash spi status is now in SPI Controller Rx reg */ *flash_spi_id = SPI_CTL_RX_REG; return rc; } /** * Function: flash_spi_number_sector * Parameters: OrgDef *pOrgDef, unsigned int nb_blocks * Purpose: Determine the number of sector * Return Value: ushort */ ushort flash_number_sector_spi(OrgDef *pOrgDef, unsigned int nb_blocks) { int i, nb_sectors = 0; for (i=0; ibd->bi_nvram_addr); flash_org = nvram->flash_org; OrgSPIFlash.sector_number = 1 << NVRAM_BFEXT(FLASH_NB_SECT, flash_org); OrgSPIFlash.sector_size = (64*1024) * (NVRAM_BFEXT(FLASH_SECT_SZ, flash_org)+1); for (i = 0; i < CFG_MAX_FLASH_SPI_BANKS; i++) { ulong flashbase = 0; pOrgDef = &OrgSPIFlash; flash_nb_blocks = sizeof (OrgSPIFlash) / sizeof (OrgDef); flash_info[i].sector_count = flash_number_sector_spi(pOrgDef, flash_nb_blocks); memset (flash_info[i].protect, 0, flash_info[i].sector_count); if (i == 0) flashbase = PHYS_FLASH_SPI_1; else panic ("configured too many flash banks!\n"); sector = 0; start_address = flashbase; flash_info[i].size = 0; for (j = 0; j < flash_nb_blocks; j++) { for (k = 0; k < pOrgDef[j].sector_number; k++) { flash_info[i].start[sector++] = start_address; start_address += pOrgDef[j].sector_size; flash_info[i].size += pOrgDef[j].sector_size; } } size += flash_info[i].size; } #if 0 /* Protect binary boot image */ flash_protect (FLAG_PROTECT_SET, CFG_FLASH_BASE, CFG_FLASH_BASE + CFG_BOOT_SIZE - 1, &flash_info[0]); #endif #if 0 /* Protect U-Boot gzipped image */ flash_protect (FLAG_PROTECT_SET, CFG_U_BOOT_BASE, CFG_U_BOOT_BASE + CFG_U_BOOT_SIZE - 1, &flash_info[0]); #endif return size; } /* flash_init_spi */ /** * Function: flash_print_info_spi * Parameters: flash_info_t * info * Purpose: Get flash info * Return Value: void */ void flash_print_info_spi (flash_info_t * info) { int i; printf ("FLASH SPI"); printf (" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); printf (" Sector Start Addresses:"); for (i = 0; i < info->sector_count; i++) { if ((i % 5) == 0) { printf ("\n "); } printf (" %08lX%s", info->start[i], info->protect[i] ? " (RO)" : " "); } printf ("\n"); } /* flash_print_info_spi */ /** * Function: flash_read_status_spi * Parameters: unsigned char *flash_spi_status * Purpose: read from flash status register * Return Value: int */ int flash_read_status_spi(unsigned char *flash_spi_status) { int rc = ERR_OK; unsigned long nowtime; /* do not reset timer, because this function might be called from another which already checks timer. This would clobber the result for the caller. Rather use delta time */ nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO ) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* read spi flash status reg */ SPI_CTL_CONF_TX = 0x00010008; /* send one byte */ SPI_CTL_CONF_RX = 0x00010008; /* receive one byte */ /*issue the command to spi flash */ SPI_CTL_TX_REG = RDSR; /* busy wait for RECEIVED_WORD bit in status reg */ nowtime = get_timer(0); while ( (SPI_CTL_STATUS_REG & RECEIVED_WORD) == 0 ) { /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO ) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ /* flash spi status is now in SPI Controller Rx reg */ *flash_spi_status = SPI_CTL_RX_REG; return rc; } /** * Function: flash_write_enable_spi * Parameters: int s_first, int s_last * Purpose: WREN command to the SPI Flash * Return Value: int */ int flash_write_enable_spi (void) { int rc = ERR_OK; unsigned long nowtime; nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ /* write enable spi flash */ SPI_CTL_CONF_TX = 0x00010008; /* send one byte (just command) */ /* reset SPI_CTL_CONF_RX - no bytes expected to be received. This step is needed because it will not be auto-reset from the previous operaton */ SPI_CTL_CONF_RX = 0x00000008; /*issue the command to spi flash */ SPI_CTL_TX_REG = WREN; nowtime = get_timer(0); /* poll until Tx FIFO is empty and SPI bus is not busy to be sure that our transmission finished */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } return rc; } /** * Function: flash_erase_spi * Parameters: int s_first, int s_last * Purpose: Erase flash * Return Value: int */ int flash_erase_spi (flash_info_t * info, int s_first, int s_last) { int iflag, cflag, prot, sect; int rc = ERR_OK; int chip1; unsigned char flash_spi_status; int low_protected_addr = 0; int erase_flash_spi_command = 0; unsigned long nowtime; /* first look for protection bits */ if ((s_first < 0) || (s_first > s_last)) { seterr_flash_spi(ERR_INVAL); return ERR_INVAL; } /* if */ prot = 0; if ( flash_read_status_spi(&flash_spi_status) == ERR_TIMOUT ) { rc = ERR_TIMOUT; return rc; } /* there are 8 variants of protection, see Spanson datasheet */ prot = (flash_spi_status & 0x1C) >> 2; if (prot != 0) { /* determine which part is protected */ int part = 64; part >>= (prot + 1); low_protected_addr = 0x800000 - (0x800000 / part); if (info->start[s_last] > low_protected_addr) { seterr_flash_spi(ERR_PROTECTED); return ERR_PROTECTED; } /* if */ } /* * Disable interrupts which might cause a timeout * here. Remember that our exception vectors are * at address 0 in the flash, and we don't want a * (ticker) exception to happen while the flash * chip is in programming mode. */ cflag = icache_status (); icache_disable (); iflag = disable_interrupts (); /* Start erase on unprotected sectors */ for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { printf ("Erasing sector %2d ... ", sect); if (info->protect[sect] == 0) { /* not protected */ volatile unsigned char *addr = (volatile unsigned char *) (info->start[sect]); /* mask MSB byte, i.e. set it to all-zero */ addr = (volatile unsigned char *) ( (unsigned int)addr & ~(0xFF << 24) ); erase_flash_spi_command = SE<<24 | (unsigned int)addr; swap_endians(&erase_flash_spi_command); /* before erase we have to write-enable SPI flash */ if ( flash_write_enable_spi() == ERR_TIMOUT ) { printf ("Cannot write-enable SPI flash.\n"); seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* arm simple, non interrupt dependent timer */ nowtime = get_timer(0); /* poll until Tx FIFO is empty and SPI bus is not busy to be sure that no other transmissions are in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* start command SPI controller seqence */ SPI_CTL_CONF_TX = 0x00010020; /* send 32 bit message (command + address) */ /* reset SPI_CTL_CONF_RX - no bytes expected to be received. This step is needed because it will not be auto-reset from the previous operaton */ SPI_CTL_CONF_RX = 0x00000000; /*issue the command to spi flash */ SPI_CTL_TX_REG = erase_flash_spi_command; /* send command + address to SPI flash via SPI controller */ /* busy wait for transaction to finish (poll status reg) */ nowtime = get_timer(0); /* poll until Tx FIFO is empty and SPI bus is not busy to be sure that our transmission finished */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* Wait until flash is ready. */ nowtime = get_timer(0); chip1 = 0; do { if ( flash_read_status_spi(&flash_spi_status) == ERR_TIMOUT ) { chip1 = TMO_SPI; break; } /* check timeout */ if (get_timer(nowtime) > CFG_FLASH_SPI_ERASE_TOUT) { chip1 = TMO_SPI; break; } /* if */ if ( !chip1 && ( (flash_spi_status & SR_WIP) == 0 ) ) chip1 = READY_SPI; } while (!chip1); /* do ... while */ if (chip1 == TMO_SPI) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ printf ("ok.\n"); } else { /* it was protected */ printf ("protected!\n"); } /* if */ } /* for */ if (ctrlc ()) printf ("User Interrupt!\n"); outahere: /* allow flash to settle - wait 10 ms */ udelay_masked (10000); if (iflag) enable_interrupts (); if (cflag) icache_enable (); return rc; } /* flash_erase_std */ /** * Function: flash_read_spi * Parameters: volatile unsigned char *dst, unsigned char *tmp_buf, int lenght * Purpose: Read SPI flash * Return Value: int */ int flash_read_spi (volatile unsigned char *gl_addr, volatile unsigned char *data, int lenght, int dirty_flag, int do_cmp) { int rc = ERR_OK; unsigned int tx_conf, rx_conf, rx_max_words, int_len, words_to_read; unsigned int nb_read = 0; /* number of read words */ int i=0, j=0; unsigned int cur_addr; unsigned int result; int error_flag = 0; unsigned long nowtime; //unsigned int kprint = 0; int read_flash_spi_command = 0; int rest = 0; char get_first_time = 0; char addr_boundary_flag = 0; volatile unsigned char *addr; /* Whatever the address, only offset is important */ addr = (volatile unsigned char*)(((unsigned int)(gl_addr)) & 0x00FFFFFF); /* maximum number of byted that SPI controller can receive in one go is size of RX FIFO - 8 bytes */ rx_max_words = 0xffff; //rx_max_bytes = 0x3f; rest = lenght % 4; int_len = lenght / 4; if ( ((unsigned int)(data) % 4) != 0) /* dest address is NOT on word boundary * we will have to read byte by byte and form * internaly one word */ addr_boundary_flag = 0; else addr_boundary_flag = 1; /* dest address is on word boundary */ while ( int_len > nb_read) { if ( (int_len - nb_read) > rx_max_words ) { tx_conf = (0x1 << 16) | 0x20; /* command + address*/ rx_conf = ( (rx_max_words) << 16) | 0x20; words_to_read = rx_max_words; } else { tx_conf = (0x1 << 16) | 0x20; /* expected number od data to be read */ rx_conf = ( (int_len - nb_read) << 16 ) | 0x20; words_to_read = int_len - nb_read; } get_first_time = 1; nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ #ifdef DEBUG_FLASH_SPI printf("tx_conf = %#x\n", tx_conf); printf("rx_conf = %#x\n", rx_conf); #endif /* configure how many bytes to send/receive */ SPI_CTL_CONF_TX = tx_conf; SPI_CTL_CONF_RX = rx_conf; /* send addr in order MSB first */ cur_addr = (unsigned int)(addr + nb_read*4); /* mask MSB byte, i.e. set it to all-zero */ cur_addr &= ~(0xFF << 24); read_flash_spi_command = READ<<24 | (unsigned int)cur_addr; swap_endians(&read_flash_spi_command); #ifdef DEBUG_FLASH_SPI //printf("read_flash_spi_command = %#x\n", read_flash_spi_command); #endif get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } SPI_CTL_TX_REG = read_flash_spi_command; /* send command + address to SPI flash via SPI controller */ #ifdef DEBUG_FLASH_SPI //printf("words_to_read = %#x\n\n", words_to_read); #endif /* and now receive the data */ for (i=0; i SPI_CTL_TMO ) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ result = SPI_CTL_RX_REG; #ifdef DEBUG_FLASH_SPI //printf("result = %#x\n", result); #endif if (do_cmp) { /* * do_cmp == 1 => flash_read_spi() was called from write_buff_spi(), * and result read should be either all 1 (if flash is clean) * or what was in data[] given to the function */ /* Check the result for errors. If there has been an error we can not go out emmidiately, we must wait SPI controller to finish transsaction, because we configured rx_config, and cannot repprogram it in the middle of transaction */ if (dirty_flag == 0) { /* flash is supposed to be clean (erased) */ if (addr_boundary_flag == 1) { /* we can read whole integer from addr, because it is on word boundary */ if ( (result & *( (unsigned int *)(data) + nb_read ) ) != *( (unsigned int *)(data) + nb_read ) ) { error_flag = 1; rc = ERR_NOT_ERASED; } } else { for (j=0; j<4; j++) { //printf("(&result)[%d] = %#x\n", j, ( (unsigned char *)&result )[j]); //printf("*( (unsigned char *)(data) + nb_read*4 + %d) = %#x\n", j, *( (unsigned char *)(data) + nb_read*4 + j) ); if ( ( ( (unsigned char *)&result )[j] & *( (unsigned char *)(data) + nb_read*4 + j) ) != *( (unsigned char *)(data) + nb_read*4 + j) ) { error_flag = 1; rc = ERR_NOT_ERASED; } } } } else /* flash is dirty (written to) */ { if (addr_boundary_flag == 1) { /* we can read whole integer from addr, because it is on word boundary */ if ( result != *( (unsigned int *)data + nb_read ) ) { error_flag = 1; rc = ERR_PROG_ERROR; } } else { for (j=0; j<4; j++) { if ( ( (unsigned char *)&result )[j] != *( (unsigned char *)data + nb_read*4 + j ) ) { error_flag = 1; rc = ERR_PROG_ERROR; } } } } } else { /* flash was not called from write_buff_spi(), * that means it was not called in compare purposes, * but we really want to retreive data. * So we will set data[nb_read] to appropriate value */ if (addr_boundary_flag == 1) { /* we can read whole integer into dest addr, because it is on word boundary */ *( (unsigned int *)(data) + nb_read ) = result; } else { /* we must write in byte by byte */ for (j=0; j<4; j++) { *( (unsigned char *)(data) + nb_read*4 + j) = ( (unsigned char *)&result )[j]; } } } /* OK, go to the next word */ nb_read ++; } /* for */ #if 0 /* print output to user to know that writing is in progress. On every 64 kb written print "W" */ if( kprint % 50 == 0) putc('\n'); putc('R'); kprint ++; #endif /* we read all the bytes we promised in rx_config, now it is safe to go out if there is an error */ if (error_flag != 0) { seterr_flash_spi(rc); return rc; } } /* while */ /* Now pick up leftover bytes, that rest from a multiple of four */ if (rest > 0) { /* how many bytes were read so far */ nb_read *= 4; tx_conf = (0x1 << 16) | 0x20; /* expected number od data to be read */ rx_conf = ( rest << 16 ) | 0x08; words_to_read = rest; get_first_time = 1; nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ /* configure how many bytes to send/receive */ SPI_CTL_CONF_TX = tx_conf; SPI_CTL_CONF_RX = rx_conf; /* send addr in order MSB first */ cur_addr = 0; for (i=2; i>=0; i--) cur_addr = (unsigned int)(addr + nb_read); /* form the command to send through SPI Controller. In case of ERASE command is composed of SE (Sector Erase) opcode plus address of the sector within SPI flash */ read_flash_spi_command = 0; read_flash_spi_command |= READ<<24 | (unsigned int)cur_addr; swap_endians(&read_flash_spi_command); get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } SPI_CTL_TX_REG = read_flash_spi_command; /* send command + address to SPI flash via SPI controller */ /* and now receive the data */ for (i=0; i SPI_CTL_TMO ) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; return rc; } /* if */ } /* while */ result = SPI_CTL_RX_REG; if (do_cmp) { /* * do_cmp == 1 => flash_read_spi() was called from write_buff_spi(), * and result read should be either all 1 (if flash is clean) * or what was in data[] given to the function */ /* Check the result for errors. If there has been an error we can not go out emmidiately, we must wait SPI controller to finish transsaction, because we configured rx_config, and cannot repprogram it in the middle of transaction */ if (dirty_flag == 0) { /* flash is supposed to be clean (erased) */ if ((result & data[nb_read]) != data[nb_read]) { error_flag = 1; rc = ERR_NOT_ERASED; } } else /* flash is dirty (written to) */ { if ( (unsigned char)result != data[nb_read] ) { error_flag = 1; rc = ERR_PROG_ERROR; } } } else { /* flash was not called from write_buff_spi(), * that means it was not called in compare purposes, * but we really want to retreive data. * So we will set data[nb_read] to appropriate value */ data[nb_read] = (char)result; } nb_read++; } /* for */ #if 0 /* print output to user to know that writing is in progress. On every 64 kb written print "W" */ if( kprint % 50 == 0) putc('\n'); putc('R'); kprint ++; #endif /* we read all the bytes we promised in rx_config, now it is safe to go out if there is an error */ if (error_flag != 0) { seterr_flash_spi(rc); return rc; } } /* if */ return rc; } /** * Function: write_buff_spi * Parameters: flash_info_t * info, uchar * src, ulong addr, ulong cnt * Purpose: Write buffer * Return Value: int */ int write_buff_spi (flash_info_t * info, uchar * src, ulong dest, ulong cnt) { volatile unsigned char *data = (volatile unsigned char *) src; volatile unsigned char *addr = (volatile unsigned char*)(((unsigned int)(dest)) & 0x00FFFFFF); int lenght = cnt; unsigned int kprint = 0; int cflag, iflag; unsigned char flash_spi_status; int rc = ERR_OK; int chip1; int i=0, j=0; int nb_written = 0; int nw_written = 0; unsigned int tx_max_words, words_to_write, int_len; unsigned int tx_conf, rx_conf; unsigned int cur_addr; unsigned long nowtime; int write_flash_spi_command = 0; int rest = 0; char get_first_time = 0; unsigned int align_bytes = 0; char addr_boundary_flag = 0; union tmp { unsigned char byte[4]; unsigned int val; } tmp; /* * Disable interrupts which might cause a timeout * here. Remember that our exception vectors are * at address 0 in the flash, and we don't want a * (ticker) exception to happen while the flash * chip is in programming mode. */ cflag = icache_status (); icache_disable (); iflag = disable_interrupts (); /* * Check if Flash is (sufficiently) erased */ /* call to SPI flash READ function with drty_flag = 0 */ if ( ( rc = flash_read_spi (addr, data, lenght, 0, 1) ) != ERR_OK ) { seterr_flash_spi(rc); goto outahere; } /* reset lenght wor WRITE operation */ lenght = cnt; /* maximum of bytes that our SPI Flash can write in one go is 256, if we start on 256 boundary. It is because the write that begun within one 256 byte region must finish in the same region in order for addresses to be well written */ tx_max_words = 0x41; /* bytes of data, without 1 byte needed for command and 3 for addr */ //tx_max_bytes = 0x3f - 1 - 3; rest = lenght % 4; int_len = lenght / 4; if ( ((unsigned int)(addr) % 4) != 0) align_bytes = 4 - ( (unsigned int)(addr) % 4 ); // nb of bytes needed to align to 4 byte boundary else { align_bytes = 0; addr_boundary_flag = 1; /* source address is on word boundary */ } if (align_bytes > 0) { if (align_bytes > lenght) { /* will do these bytes in the "rest" loop */ align_bytes = 0; } else { int_len = (lenght - align_bytes) / 4; rest = (lenght - align_bytes) % 4; } } //printf("rest = %#x\n", rest); //printf("int_len = %#x\n", int_len); //printf("align_bytes = %#x\n", align_bytes); //getc(); /* ALIGN (BYTE-BY-BYTE) LOOP */ while (align_bytes > 0) { tx_conf = ( (align_bytes + 1 + 3) << 16 ) | 0x08; rx_conf = 0x0; words_to_write = align_bytes; /* First write-enable the SPI flash */ if ( flash_write_enable_spi() == ERR_TIMOUT ) { printf ("Cannot write-enable SPI flash\n"); seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* And then program flash */ get_first_time = 1; nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* while */ SPI_CTL_CONF_TX = tx_conf; SPI_CTL_CONF_RX = rx_conf; /* first send out command */ get_first_time = 1; while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = PP; cur_addr = (unsigned int)addr; /* send addr in order MSB first */ for (i=2; i>=0; i--) { get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = ( (volatile unsigned char *)(&cur_addr) )[i]; } for (i=0; i < words_to_write; i++) { /* and send byte of data to be written */ get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = data[nb_written]; nb_written++; align_bytes--; } /* for */ /* arm simple, non interrupt dependent timer */ get_first_time = 1; /* poll until Tx FIFO is empty and SPI bus is not busy to be sure that our transmission finished */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* wait until flash is ready */ /* arm simple, non interrupt dependent timer */ nowtime = get_timer(0); chip1 = 0; do { if ( flash_read_status_spi(&flash_spi_status) == ERR_TIMOUT) { chip1 = TMO_SPI; break; } /* check timeout */ if (get_timer(nowtime) > CFG_FLASH_SPI_WRITE_TOUT) { chip1 = TMO_SPI; break; } if ( !chip1 && ( (flash_spi_status & SR_WIP) == 0 ) ) chip1 = READY_SPI; } while (!chip1); /* do ... while */ if (chip1 == TMO_SPI) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } } /*while */ /* WORD (4-byte) LOOP */ while (int_len > nw_written) { if ( (int_len - nw_written) > tx_max_words ) { tx_conf = (tx_max_words << 16) | 0x20; rx_conf = 0x0; words_to_write = tx_max_words - 1; } else { /* 1 byte for the command and 3 bytes of addr per data to be read */ tx_conf = ( (1 + (int_len - nw_written) ) << 16 ) | 0x20; /* expected number od data to be read */ rx_conf = 0x0; words_to_write = int_len - nw_written; } /* Check if we will do writing within same 256 byte region. It is not allowed to cross to next region within same PP operation. If we are crossing to the next region, lower the bytes_to_write, in order to finish writing on 256 byte region boundary (i.e. to do all the writing in the same region in which we are starting). */ cur_addr = (unsigned int)(addr + nb_written + nw_written*4); if ( (cur_addr % 256) + words_to_write*4 > 256) { words_to_write = ( 256 - (cur_addr % 256) ) / 4; tx_conf = ( (words_to_write + 1) << 16) | 0x20; } /* First write-enable the SPI flash */ if ( flash_write_enable_spi() == ERR_TIMOUT ) { printf ("Cannot write-enable SPI flash\n"); seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* And then program flash */ get_first_time = 1; nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* while */ SPI_CTL_CONF_TX = tx_conf; /* send 32 bit message (command + address) */ SPI_CTL_CONF_RX = rx_conf; /* send addr in order MSB first */ cur_addr = (unsigned int)(addr + nb_written + nw_written*4); /* mask MSB byte, i.e. set it to all-zero */ cur_addr &= ~(0xFF << 24); write_flash_spi_command = PP<<24 | (unsigned int)cur_addr; swap_endians(&write_flash_spi_command); /* first send out command */ get_first_time = 1; while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = write_flash_spi_command; for (i=0; i < words_to_write; i++) { /* and send byte of data to be written */ get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } if (addr_boundary_flag == 0) { /* source addr is not on int boundary, so we must take 4 bytes * byte-by-byte */ for (j=0; j < 4; j++) { tmp.byte[j] = *( (unsigned char *)(data + nb_written + nw_written*4 + j) ); } SPI_CTL_TX_REG = tmp.val; } else { /* since source addr is on word boundary, we can cast it to int pointer, * and take all 4 bytes in one go */ SPI_CTL_TX_REG = *( (unsigned int *)(data + nb_written + nw_written*4) ); } nw_written++; } /* for */ /* print output to user to know that writing is in progress. On every 256*256b written print "." */ if(kprint && (kprint % 256 == 0)) puts("."); kprint ++; /* arm simple, non interrupt dependent timer */ get_first_time = 1; /* poll until Tx FIFO is empty and SPI bus is not busy to be sure that our transmission finished */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* wait until flash is ready */ /* arm simple, non interrupt dependent timer */ nowtime = get_timer(0); chip1 = 0; do { if ( flash_read_status_spi(&flash_spi_status) == ERR_TIMOUT) { chip1 = TMO_SPI; break; } /* check timeout */ if (get_timer(nowtime) > CFG_FLASH_SPI_WRITE_TOUT) { chip1 = TMO_SPI; break; } if ( !chip1 && ( (flash_spi_status & SR_WIP) == 0 ) ) chip1 = READY_SPI; } while (!chip1); /* do ... while */ if (chip1 == TMO_SPI) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } } /* while */ /* REST (BYTE-BY-BYTE) LOOP */ nb_written = nb_written + nw_written*4; while (rest > 0) { tx_conf = ( (rest + 1 + 3) << 16 ) | 0x08; rx_conf = 0x0; words_to_write = rest; /* Check if we will do writing within same 256 byte region. It is not allowed to cross to next region within same PP operation. If we are crossing to the next region, lower the bytes_to_write, in order to finish writing on 256 byte region boundary (i.e. to do all the writing in the same region in which we are starting). */ cur_addr = (unsigned int)(addr + nb_written); if ( (cur_addr % 256) + words_to_write > 256) { words_to_write = 256 - (cur_addr % 256); tx_conf = ( (words_to_write + 1 + 3) << 16) | 0x8; } /* First write-enable the SPI flash */ if ( flash_write_enable_spi() == ERR_TIMOUT ) { printf ("Cannot write-enable SPI flash\n"); seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* And then program flash */ get_first_time = 1; nowtime = get_timer(0); /* poll until Tx and Rx FIFOs are empty and SPI bus is not busy to be sure that no other transmissoin is in progress */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_RX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* while */ SPI_CTL_CONF_TX = tx_conf; SPI_CTL_CONF_RX = rx_conf; /* first send out command */ get_first_time = 1; while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = PP; /* send addr in order MSB first */ for (i=2; i>=0; i--) { get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = ( (volatile unsigned char *)(&cur_addr) )[i]; } for (i=0; i < words_to_write; i++) { /* and send byte of data to be written */ get_first_time = 1; while ( (SPI_CTL_STATUS_REG & FULL_FIFO_TX) != 0 ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } if ( get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } SPI_CTL_TX_REG = data[nb_written]; nb_written++; rest--; } /* for */ /* arm simple, non interrupt dependent timer */ get_first_time = 1; /* poll until Tx FIFO is empty and SPI bus is not busy to be sure that our transmission finished */ while ( ( (SPI_CTL_STATUS_REG & EMPTY_FIFO_TX) == 0 ) || ( (SPI_CTL_STATUS_REG & BUSY_MASTER) != 0 ) ) { if (get_first_time == 1) { nowtime = get_timer(0); get_first_time = 0; } /* check timeout */ if (get_timer(nowtime) > SPI_CTL_TMO) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } /* if */ } /* wait until flash is ready */ /* arm simple, non interrupt dependent timer */ nowtime = get_timer(0); chip1 = 0; do { if ( flash_read_status_spi(&flash_spi_status) == ERR_TIMOUT) { chip1 = TMO_SPI; break; } /* check timeout */ if (get_timer(nowtime) > CFG_FLASH_SPI_WRITE_TOUT) { chip1 = TMO_SPI; break; } if ( !chip1 && ( (flash_spi_status & SR_WIP) == 0 ) ) chip1 = READY_SPI; } while (!chip1); /* do ... while */ if (chip1 == TMO_SPI) { seterr_flash_spi(ERR_TIMOUT); rc = ERR_TIMOUT; goto outahere; } } /*while */ /* * read the data to verify the write */ /* call to SPI flash READ function with drty_flag = 1 */ if ( ( rc = flash_read_spi (addr, data, lenght, 1, 1) ) != ERR_OK ) { seterr_flash_spi(rc); goto outahere; } /* if */ putc(' '); outahere: if (iflag) enable_interrupts (); if (cflag) icache_enable (); return rc; } /* write_buff_spi */