proxmark3/armsrc/flashmem.c

417 lines
10 KiB
C
Raw Normal View History

2018-02-13 21:12:28 +08:00
#include "flashmem.h"
/* here: use NCPS2 @ PA10: */
2018-02-21 15:30:47 +08:00
#define SPI_CSR_NUM 2 // Chip Select register[] 0,1,2,3 (at91samv512 has 4)
/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */
#define PCS_0 ((0<<0)|(1<<1)|(1<<2)|(1<<3)) // 0xE - 1110
#define PCS_1 ((1<<0)|(0<<1)|(1<<2)|(1<<3)) // 0xD - 1101
#define PCS_2 ((1<<0)|(1<<1)|(0<<2)|(1<<3)) // 0xB - 1011
#define PCS_3 ((1<<0)|(1<<1)|(1<<2)|(0<<3)) // 0x7 - 0111
2018-03-31 16:35:40 +08:00
// TODO
#if (SPI_CSR_NUM == 0)
#define SPI_MR_PCS PCS_0
#elif (SPI_CSR_NUM == 1)
#define SPI_MR_PCS PCS_1
#elif (SPI_CSR_NUM == 2)
#define SPI_MR_PCS PCS_2
#elif (SPI_CSR_NUM == 3)
#define SPI_MR_PCS PCS_3
#else
#error "SPI_CSR_NUM invalid"
// not realy - when using an external address decoder...
// but this code takes over the complete SPI-interace anyway
#endif
/*
<EFBFBD><EFBFBD>ȡָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>һ<EFBFBD><EFBFBD>λ<EFBFBD>ÿ<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>оƬ<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>
ҳдָ<EFBFBD>ÿ<EFBFBD><EFBFBD>д<EFBFBD><EFBFBD>Ϊ1-256<EFBFBD>ֽڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Dz<EFBFBD><EFBFBD>ܿ<EFBFBD>Խ256<EFBFBD>ֽڱ߽<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CS<EFBFBD><EFBFBD><EFBFBD>ߣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>򲻻<EFBFBD>ִ<EFBFBD><EFBFBD>
*/
2018-02-13 21:12:28 +08:00
2018-03-31 16:35:40 +08:00
void FlashSetup(void) {
// PA1 -> SPI_NCS3 chip select (MEM)
// PA10 -> SPI_NCS2 chip select (LCD)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// Disable PIO control of the following pins, allows use by the SPI peripheral
2018-07-04 18:19:29 +08:00
AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// Pull-up Enable
2018-07-04 18:19:29 +08:00
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// Peripheral A
2018-07-04 18:19:29 +08:00
AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK);
// Peripheral B
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// NPCS2 Mode 0
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xB << 16) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
// 8 bit
AT91C_BASE_SPI->SPI_CSR[2] =
( 0 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 0 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
( 0 << 4) | // Bits per Transfer (8 bits)
( 1 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
// read first, empty buffer
2018-03-31 16:35:40 +08:00
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
2018-02-15 16:19:13 +08:00
}
2018-03-31 16:35:40 +08:00
void FlashStop(void) {
//* Reset all the Chip Select register
AT91C_BASE_SPI->SPI_CSR[0] = 0;
AT91C_BASE_SPI->SPI_CSR[1] = 0;
AT91C_BASE_SPI->SPI_CSR[2] = 0;
AT91C_BASE_SPI->SPI_CSR[3] = 0;
// Reset the SPI mode
AT91C_BASE_SPI->SPI_MR = 0;
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
2018-03-31 16:35:40 +08:00
if ( MF_DBGLEVEL > 3 ) Dbprintf("FlashStop");
StopTicks();
2018-02-15 16:19:13 +08:00
}
2018-03-31 16:35:40 +08:00
// send one byte over SPI
uint16_t FlashSendByte(uint32_t data) {
uint16_t incoming = 0;
WDT_HIT();
2018-02-21 15:30:47 +08:00
// wait until SPI is ready for transfer
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
2018-02-21 15:30:47 +08:00
// send the data
AT91C_BASE_SPI->SPI_TDR = data;
// wait recive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0)
WDT_HIT();
2018-02-21 15:30:47 +08:00
// reading incoming data
incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
2018-02-21 15:30:47 +08:00
return incoming;
}
2018-03-31 16:35:40 +08:00
// send last byte over SPI
uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER);
}
2018-03-31 16:35:40 +08:00
// read state register 1
uint8_t Flash_ReadStat1(void) {
FlashSendByte(READSTAT1);
uint8_t stat1 = FlashSendLastByte(0xFF);
// if ( MF_DBGLEVEL > 3 ) Dbprintf("stat1 [%02x]", stat1);
return stat1;
}
2018-03-31 16:35:40 +08:00
// read state register 2
uint8_t Flash_ReadStat2(void) {
FlashSendByte(READSTAT2);
uint8_t stat2 = FlashSendLastByte(0xFF);
// if ( MF_DBGLEVEL > 3 ) Dbprintf("stat2 [%02x]", stat2);
return stat2;
2018-02-15 16:19:13 +08:00
}
2018-03-31 16:35:40 +08:00
// determine whether FLASHMEM is busy
bool Flash_CheckBusy(uint16_t times) {
2018-03-31 16:35:40 +08:00
bool ret = (Flash_ReadStat1() & BUSY);
2018-03-31 16:35:40 +08:00
if (!ret || !times || !(times--))
return ret;
2018-03-31 16:35:40 +08:00
while (times) {
WDT_HIT();
SpinDelay(1);
2018-03-31 16:35:40 +08:00
ret = (Flash_ReadStat1() & BUSY);
if (!ret)
break;
times--;
}
2018-03-31 16:35:40 +08:00
return ret;
2018-02-15 16:19:13 +08:00
}
// read ID out
uint8_t Flash_ReadID(void) {
if (Flash_CheckBusy(100)) return 0;
// Manufacture ID / device ID
2018-03-31 16:35:40 +08:00
FlashSendByte(ID);
FlashSendByte(0x00);
FlashSendByte(0x00);
FlashSendByte(0x00);
uint8_t man_id = FlashSendByte(0xFF);
2018-05-22 18:10:02 +08:00
uint8_t dev_id = FlashSendLastByte(0xFF);
2018-03-31 16:35:40 +08:00
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash ReadID | Man ID %02x | Device ID %02x", man_id, dev_id);
if ( (man_id == WINBOND_MANID ) && (dev_id == WINBOND_DEVID) )
return dev_id;
2018-03-31 16:35:40 +08:00
return 0;
}
// read unique id for chip.
void Flash_UniqueID(uint8_t *uid) {
if (Flash_CheckBusy(100)) return;
2018-03-31 16:35:40 +08:00
// reading unique serial number
FlashSendByte(UNIQUE_ID);
2018-04-08 16:24:24 +08:00
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
uid[7] = FlashSendByte(0xFF);
uid[6] = FlashSendByte(0xFF);
uid[5] = FlashSendByte(0xFF);
uid[4] = FlashSendByte(0xFF);
2018-03-31 16:35:40 +08:00
uid[3] = FlashSendByte(0xFF);
uid[2] = FlashSendByte(0xFF);
uid[1] = FlashSendByte(0xFF);
uid[0] = FlashSendLastByte(0xFF);
}
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
if (!FlashInit()) return 0;
Flash_ReadStat1();
// length should never be zero
if (!len || Flash_CheckBusy(100)) return 0;
FlashSendByte(READDATA);
2018-03-31 16:35:40 +08:00
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
2018-03-31 16:35:40 +08:00
out[i] = FlashSendByte(0xFF);
2018-03-31 16:35:40 +08:00
out[i] = FlashSendLastByte(0xFF);
FlashStop();
return len;
}
// Write data can only program one page. A page has 256 bytes.
// if len > 256, it might wrap around and overwrite pos 0.
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) {
2018-02-15 16:19:13 +08:00
// length should never be zero
if (!len)
return 0;
// Max 256 bytes write
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF)+len, len );
return 0;
}
// out-of-range
if ( (( address >> 16 ) & 0xFF ) > MAX_BLOCKS) {
Dbprintf("Flash_WriteData, block out-of-range");
return 0;
}
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return 0;
}
Flash_ReadStat1();
2018-02-15 16:19:13 +08:00
Flash_WriteEnable();
FlashSendByte(PAGEPROG);
2018-03-31 16:35:40 +08:00
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
2018-02-15 16:19:13 +08:00
uint16_t i = 0;
for (; i < (len - 1); i++)
2018-03-31 16:35:40 +08:00
FlashSendByte(in[i]);
2018-02-15 16:19:13 +08:00
2018-03-31 16:35:40 +08:00
FlashSendLastByte(in[i]);
FlashStop();
return len;
2018-02-13 21:12:28 +08:00
}
bool Flash_WipeMemoryPage(uint8_t page) {
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. One block erase takes 1s ( 1000ms )
Flash_WriteEnable(); Flash_Erase64k(page); Flash_CheckBusy(1000);
FlashStop();
return true;
}
// Wipes flash memory completely, fills with 0xFF
bool Flash_WipeMemory() {
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. Four blocks
// one block erase takes 1s ( 1000ms )
Flash_WriteEnable(); Flash_Erase64k(0); Flash_CheckBusy(1000);
Flash_WriteEnable(); Flash_Erase64k(1); Flash_CheckBusy(1000);
Flash_WriteEnable(); Flash_Erase64k(2); Flash_CheckBusy(1000);
Flash_WriteEnable(); Flash_Erase64k(3); Flash_CheckBusy(1000);
FlashStop();
return true;
}
// enable the flash write
2018-03-31 16:35:40 +08:00
void Flash_WriteEnable() {
2018-05-22 18:10:02 +08:00
FlashSendLastByte(WRITEENABLE);
2018-03-31 16:35:40 +08:00
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash Write enabled");
2018-02-13 21:12:28 +08:00
}
// erase 4K at one time
// execution time: 0.8ms / 800us
bool Flash_Erase4k(uint8_t block, uint8_t sector) {
if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false;
2018-02-13 21:12:28 +08:00
FlashSendByte(SECTORERASE);
FlashSendByte(block);
FlashSendByte(sector << 4);
FlashSendLastByte(00);
return true;
2018-02-13 21:12:28 +08:00
}
/*
// erase 32K at one time
// execution time: 0,3s / 300ms
2018-03-31 16:35:40 +08:00
bool Flash_Erase32k(uint32_t address) {
if (address & (32*1024 - 1)) {
if ( MF_DBGLEVEL > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK32ERASE);
2018-03-31 16:35:40 +08:00
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendLastByte((address >> 0) & 0xFF);
2018-02-13 21:12:28 +08:00
return true;
}
*/
2018-02-13 21:12:28 +08:00
// erase 64k at one time
// since a block is 64kb, and there is four blocks.
// we only need block number, as MSB
// execution time: 1s / 1000ms
// 0x00 00 00 -- 0x 00 FF FF == block 0
// 0x01 00 00 -- 0x 01 FF FF == block 1
// 0x02 00 00 -- 0x 02 FF FF == block 2
// 0x03 00 00 -- 0x 03 FF FF == block 3
bool Flash_Erase64k(uint8_t block) {
if (block > MAX_BLOCKS) return false;
FlashSendByte(BLOCK64ERASE);
FlashSendByte(block);
FlashSendByte(0x00);
FlashSendLastByte(0x00);
return true;
}
2018-02-13 21:12:28 +08:00
2018-03-31 16:35:40 +08:00
// Erase chip
void Flash_EraseChip(void) {
FlashSendLastByte(CHIPERASE);
2018-02-13 21:12:28 +08:00
}
// initialize
2018-03-31 16:35:40 +08:00
bool FlashInit(void) {
FlashSetup();
2018-02-13 21:12:28 +08:00
2018-03-31 16:35:40 +08:00
StartTicks();
if (Flash_CheckBusy(100)) {
2018-03-31 16:35:40 +08:00
StopTicks();
return false;
2018-03-31 16:35:40 +08:00
}
2018-02-13 21:12:28 +08:00
2018-03-31 16:35:40 +08:00
if ( MF_DBGLEVEL > 3 ) Dbprintf("FlashInit OK");
2018-02-13 21:12:28 +08:00
return true;
}
2018-03-31 16:35:40 +08:00
void Flashmem_print_status(void) {
DbpString("Flash memory");
if (!FlashInit()) {
DbpString(" init....................FAIL");
return;
}
DbpString(" init....................OK");
uint8_t dev_id = Flash_ReadID();
switch (dev_id) {
case 0x11 :
DbpString(" Memory size.............2 mbits / 256kb");
break;
case 0x10 :
DbpString(" Memory size..... .......1 mbits / 128kb");
break;
case 0x05 :
DbpString(" Memory size.............512 kbits / 64kb");
break;
default :
DbpString(" Device ID............... --> Unknown <--");
break;
}
2018-04-08 16:24:24 +08:00
uint8_t uid[8] = {0,0,0,0,0,0,0,0};
2018-03-31 16:35:40 +08:00
Flash_UniqueID(uid);
2018-04-08 16:24:24 +08:00
Dbprintf(" Unique ID...............0x%02x%02x%02x%02x%02x%02x%02x%02x",
uid[7], uid[6], uid[5], uid[4],
uid[3], uid[2], uid[1], uid[0]
);
2018-03-31 16:35:40 +08:00
FlashStop();
2018-03-31 16:35:40 +08:00
}