mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 10:37:23 -07:00
Bootrom: Enable serial number from flash
* Add `.ramfunc` section to bootrom loader script * exclude spiffs functionality from flashmem.h/flashmem.c (allows bootrom to use flashmem) * hide unused tick.h / flashmem.h functions from bootrom (not technically necessary; see comments) * bootrom: add source files, include path, and defines when `PLATFORM_DEFS` defines `WITH_FLASH` * Define `AS_BOOTROM` to indicate code is building for bootrom
This commit is contained in:
parent
5784c8de77
commit
44676bde72
9 changed files with 373 additions and 272 deletions
628
common_arm/flashmem.c
Normal file
628
common_arm/flashmem.c
Normal file
|
@ -0,0 +1,628 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Borrowed initially from Arduino SPIFlash Library v.2.5.0
|
||||
// Copyright (C) 2015 by Prajwal Bhattaram.
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// 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 3 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.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "flashmem.h"
|
||||
#include "pmflash.h"
|
||||
|
||||
#include "proxmark3_arm.h"
|
||||
#include "ticks.h"
|
||||
|
||||
#ifndef AS_BOOTROM
|
||||
#include "dbprint.h"
|
||||
#endif // AS_BOOTROM
|
||||
|
||||
#include "string.h"
|
||||
#include "usb_cdc.h"
|
||||
|
||||
/* here: use NCPS2 @ PA10: */
|
||||
#define SPI_CSR_NUM 2
|
||||
#define SPI_PCS(npcs) ((~(1 << (npcs)) & 0xF) << 16)
|
||||
/// Calculates the value of the CSR SCBR field given the baudrate and MCK.
|
||||
#define SPI_SCBR(baudrate, masterClock) ((uint32_t) ((masterClock) / (baudrate)) << 8)
|
||||
/// Calculates the value of the CSR DLYBS field given the desired delay (in ns)
|
||||
#define SPI_DLYBS(delay, masterClock) ((uint32_t) ((((masterClock) / 1000000) * (delay)) / 1000) << 16)
|
||||
/// Calculates the value of the CSR DLYBCT field given the desired delay (in ns)
|
||||
#define SPI_DLYBCT(delay, masterClock) ((uint32_t) ((((masterClock) / 1000000) * (delay)) / 32000) << 24)
|
||||
|
||||
static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
|
||||
#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST)
|
||||
|
||||
#ifndef AS_BOOTROM
|
||||
|
||||
void FlashmemSetSpiBaudrate(uint32_t baudrate) {
|
||||
FLASHMEM_SPIBAUDRATE = baudrate;
|
||||
Dbprintf("Spi Baudrate : %dMHz", FLASHMEM_SPIBAUDRATE / 1000000);
|
||||
}
|
||||
|
||||
// read ID out
|
||||
uint8_t Flash_ReadID(void) {
|
||||
|
||||
if (Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
|
||||
|
||||
// Manufacture ID / device ID
|
||||
FlashSendByte(ID);
|
||||
FlashSendByte(0x00);
|
||||
FlashSendByte(0x00);
|
||||
FlashSendByte(0x00);
|
||||
|
||||
uint8_t man_id = FlashSendByte(0xFF);
|
||||
uint8_t dev_id = FlashSendLastByte(0xFF);
|
||||
|
||||
if (g_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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
|
||||
|
||||
if (!FlashInit()) return 0;
|
||||
|
||||
// length should never be zero
|
||||
if (!len || Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
|
||||
|
||||
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
|
||||
|
||||
FlashSendByte(cmd);
|
||||
Flash_TransferAdresse(address);
|
||||
|
||||
if (FASTFLASH) {
|
||||
FlashSendByte(DUMMYBYTE);
|
||||
}
|
||||
|
||||
uint16_t i = 0;
|
||||
for (; i < (len - 1); i++)
|
||||
out[i] = FlashSendByte(0xFF);
|
||||
|
||||
out[i] = FlashSendLastByte(0xFF);
|
||||
FlashStop();
|
||||
return len;
|
||||
}
|
||||
|
||||
void Flash_TransferAdresse(uint32_t address) {
|
||||
FlashSendByte((address >> 16) & 0xFF);
|
||||
FlashSendByte((address >> 8) & 0xFF);
|
||||
FlashSendByte((address >> 0) & 0xFF);
|
||||
}
|
||||
|
||||
/* This ensures we can ReadData without having to cycle through initialization every time */
|
||||
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) {
|
||||
|
||||
// length should never be zero
|
||||
if (!len) return 0;
|
||||
|
||||
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
|
||||
|
||||
FlashSendByte(cmd);
|
||||
Flash_TransferAdresse(address);
|
||||
|
||||
if (FASTFLASH) {
|
||||
FlashSendByte(DUMMYBYTE);
|
||||
}
|
||||
|
||||
uint16_t i = 0;
|
||||
for (; i < (len - 1); i++)
|
||||
out[i] = FlashSendByte(0xFF);
|
||||
|
||||
out[i] = FlashSendLastByte(0xFF);
|
||||
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) {
|
||||
|
||||
// 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 (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
|
||||
Flash_WriteEnable();
|
||||
|
||||
FlashSendByte(PAGEPROG);
|
||||
FlashSendByte((address >> 16) & 0xFF);
|
||||
FlashSendByte((address >> 8) & 0xFF);
|
||||
FlashSendByte((address >> 0) & 0xFF);
|
||||
|
||||
uint16_t i = 0;
|
||||
for (; i < (len - 1); i++)
|
||||
FlashSendByte(in[i]);
|
||||
|
||||
FlashSendLastByte(in[i]);
|
||||
|
||||
FlashStop();
|
||||
return len;
|
||||
}
|
||||
|
||||
// length should never be zero
|
||||
// Max 256 bytes write
|
||||
// out-of-range
|
||||
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len) {
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (((address & 0xFF) + len) > 256) {
|
||||
Dbprintf("Flash_WriteDataCont 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
|
||||
Dbprintf("Flash_WriteDataCont, block out-of-range");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FlashSendByte(PAGEPROG);
|
||||
FlashSendByte((address >> 16) & 0xFF);
|
||||
FlashSendByte((address >> 8) & 0xFF);
|
||||
FlashSendByte((address >> 0) & 0xFF);
|
||||
|
||||
uint16_t i = 0;
|
||||
for (; i < (len - 1); i++)
|
||||
FlashSendByte(in[i]);
|
||||
|
||||
FlashSendLastByte(in[i]);
|
||||
return len;
|
||||
}
|
||||
|
||||
// assumes valid start 256 based 00 address
|
||||
//
|
||||
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len) {
|
||||
|
||||
bool isok;
|
||||
uint16_t res, bytes_sent = 0, bytes_remaining = len;
|
||||
uint8_t buf[FLASH_MEM_BLOCK_SIZE];
|
||||
while (bytes_remaining > 0) {
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
|
||||
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
|
||||
|
||||
memcpy(buf, in + bytes_sent, bytes_in_packet);
|
||||
|
||||
res = Flash_WriteDataCont(address + bytes_sent, buf, bytes_in_packet);
|
||||
|
||||
bytes_remaining -= bytes_in_packet;
|
||||
bytes_sent += bytes_in_packet;
|
||||
|
||||
isok = (res == bytes_in_packet);
|
||||
|
||||
if (!isok)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
FlashStop();
|
||||
return len;
|
||||
}
|
||||
|
||||
// WARNING -- if callers are using a file system (such as SPIFFS),
|
||||
// they should inform the file system of this change
|
||||
// e.g., rdv40_spiffs_check()
|
||||
bool Flash_WipeMemoryPage(uint8_t page) {
|
||||
if (!FlashInit()) {
|
||||
if (g_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(BUSY_TIMEOUT);
|
||||
|
||||
FlashStop();
|
||||
|
||||
return true;
|
||||
}
|
||||
// Wipes flash memory completely, fills with 0xFF
|
||||
bool Flash_WipeMemory(void) {
|
||||
if (!FlashInit()) {
|
||||
if (g_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(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
Flash_Erase64k(1);
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
Flash_Erase64k(2);
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
Flash_Erase64k(3);
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
|
||||
FlashStop();
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable the flash write
|
||||
void Flash_WriteEnable(void) {
|
||||
FlashSendLastByte(WRITEENABLE);
|
||||
if (g_dbglevel > 3) Dbprintf("Flash Write enabled");
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
FlashSendByte(SECTORERASE);
|
||||
FlashSendByte(block);
|
||||
FlashSendByte(sector << 4);
|
||||
FlashSendLastByte(00);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
// erase 32K at one time
|
||||
// execution time: 0,3s / 300ms
|
||||
bool Flash_Erase32k(uint32_t address) {
|
||||
if (address & (32*1024 - 1)) {
|
||||
if ( g_dbglevel > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096");
|
||||
return false;
|
||||
}
|
||||
FlashSendByte(BLOCK32ERASE);
|
||||
FlashSendByte((address >> 16) & 0xFF);
|
||||
FlashSendByte((address >> 8) & 0xFF);
|
||||
FlashSendLastByte((address >> 0) & 0xFF);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/*
|
||||
// Erase chip
|
||||
void Flash_EraseChip(void) {
|
||||
FlashSendLastByte(CHIPERASE);
|
||||
}
|
||||
*/
|
||||
|
||||
void Flashmem_print_status(void) {
|
||||
DbpString(_CYAN_("Flash memory"));
|
||||
Dbprintf(" Baudrate................ " _GREEN_("%d MHz"), FLASHMEM_SPIBAUDRATE / 1000000);
|
||||
|
||||
if (!FlashInit()) {
|
||||
DbpString(" Init.................... " _RED_("FAILED"));
|
||||
return;
|
||||
}
|
||||
DbpString(" Init.................... " _GREEN_("OK"));
|
||||
|
||||
uint8_t dev_id = Flash_ReadID();
|
||||
switch (dev_id) {
|
||||
case 0x11 :
|
||||
DbpString(" Memory size............. " _YELLOW_("2 mbits / 256 kb"));
|
||||
break;
|
||||
case 0x10 :
|
||||
DbpString(" Memory size..... ....... " _YELLOW_("1 mbits / 128 kb"));
|
||||
break;
|
||||
case 0x05 :
|
||||
DbpString(" Memory size............. " _YELLOW_("512 kbits / 64 kb"));
|
||||
break;
|
||||
default :
|
||||
DbpString(" Device ID............... " _YELLOW_(" --> Unknown <--"));
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
Flash_UniqueID(uid);
|
||||
Dbprintf( " Unique ID............... " _YELLOW_("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]
|
||||
);
|
||||
|
||||
FlashStop();
|
||||
}
|
||||
|
||||
void Flashmem_print_info(void) {
|
||||
|
||||
if (!FlashInit()) return;
|
||||
|
||||
DbpString(_CYAN_("Flash memory dictionary loaded"));
|
||||
|
||||
// load dictionary offsets.
|
||||
uint8_t keysum[2];
|
||||
uint16_t num;
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
uint16_t isok = Flash_ReadDataCont(DEFAULT_MF_KEYS_OFFSET, keysum, 2);
|
||||
if (isok == 2) {
|
||||
num = ((keysum[1] << 8) | keysum[0]);
|
||||
if (num != 0xFFFF && num != 0x0)
|
||||
Dbprintf(" Mifare.................. "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_MF_KEYS_MAX);
|
||||
}
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
isok = Flash_ReadDataCont(DEFAULT_T55XX_KEYS_OFFSET, keysum, 2);
|
||||
if (isok == 2) {
|
||||
num = ((keysum[1] << 8) | keysum[0]);
|
||||
if (num != 0xFFFF && num != 0x0)
|
||||
Dbprintf(" T55x7................... "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_T55XX_KEYS_MAX);
|
||||
}
|
||||
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
isok = Flash_ReadDataCont(DEFAULT_ICLASS_KEYS_OFFSET, keysum, 2);
|
||||
if (isok == 2) {
|
||||
num = ((keysum[1] << 8) | keysum[0]);
|
||||
if (num != 0xFFFF && num != 0x0)
|
||||
Dbprintf(" iClass.................. "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_ICLASS_KEYS_MAX);
|
||||
}
|
||||
|
||||
FlashStop();
|
||||
}
|
||||
|
||||
#endif // #ifndef AS_BOOTROM
|
||||
|
||||
|
||||
// initialize
|
||||
bool FlashInit(void) {
|
||||
FlashSetup(FLASHMEM_SPIBAUDRATE);
|
||||
|
||||
StartTicks();
|
||||
|
||||
if (Flash_CheckBusy(BUSY_TIMEOUT)) {
|
||||
StopTicks();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// read unique id for chip.
|
||||
void Flash_UniqueID(uint8_t *uid) {
|
||||
|
||||
if (Flash_CheckBusy(BUSY_TIMEOUT)) return;
|
||||
|
||||
// reading unique serial number
|
||||
FlashSendByte(UNIQUE_ID);
|
||||
FlashSendByte(0xFF);
|
||||
FlashSendByte(0xFF);
|
||||
FlashSendByte(0xFF);
|
||||
FlashSendByte(0xFF);
|
||||
|
||||
uid[7] = FlashSendByte(0xFF);
|
||||
uid[6] = FlashSendByte(0xFF);
|
||||
uid[5] = FlashSendByte(0xFF);
|
||||
uid[4] = FlashSendByte(0xFF);
|
||||
uid[3] = FlashSendByte(0xFF);
|
||||
uid[2] = FlashSendByte(0xFF);
|
||||
uid[1] = FlashSendByte(0xFF);
|
||||
uid[0] = FlashSendLastByte(0xFF);
|
||||
}
|
||||
|
||||
void FlashStop(void) {
|
||||
//Bof
|
||||
//* 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;
|
||||
|
||||
#ifndef AS_BOOTROM
|
||||
if (g_dbglevel > 3) Dbprintf("FlashStop");
|
||||
#endif // AS_BOOTROM
|
||||
|
||||
StopTicks();
|
||||
}
|
||||
|
||||
void FlashSetup(uint32_t baudrate) {
|
||||
//WDT_DISABLE
|
||||
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||
|
||||
// PA10 -> SPI_NCS2 chip select (FLASHMEM)
|
||||
// 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
|
||||
AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
|
||||
|
||||
// Pull-up Enable
|
||||
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
|
||||
|
||||
// Peripheral A
|
||||
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);
|
||||
|
||||
|
||||
//reset spi needs double SWRST, see atmel's errata on this case
|
||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
|
||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
|
||||
|
||||
// Enable SPI
|
||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
|
||||
|
||||
// NPCS2 Mode 0
|
||||
AT91C_BASE_SPI->SPI_MR =
|
||||
(0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT:
|
||||
// If DLYBCS is less than or equal to six, six MCK periods
|
||||
// will be inserted by default.
|
||||
SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
|
||||
(0 << 7) | // Disable LLB (1=MOSI2MISO test mode)
|
||||
(1 << 4) | // Disable ModeFault Protection
|
||||
(0 << 3) | // makes spi operate at MCK (1 is MCK/2)
|
||||
(0 << 2) | // Chip selects connected directly to peripheral
|
||||
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
|
||||
AT91C_SPI_MSTR; // Master Mode
|
||||
|
||||
uint8_t csaat = 1;
|
||||
uint32_t dlybct = 0;
|
||||
uint8_t ncpha = 1;
|
||||
uint8_t cpol = 0;
|
||||
if (baudrate > FLASH_MINFAST) {
|
||||
baudrate = FLASH_FASTBAUD;
|
||||
//csaat = 0;
|
||||
dlybct = 1500;
|
||||
ncpha = 0;
|
||||
cpol = 0;
|
||||
}
|
||||
|
||||
AT91C_BASE_SPI->SPI_CSR[2] =
|
||||
SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods)
|
||||
SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock
|
||||
SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection
|
||||
AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits)
|
||||
//AT91C_SPI_CSAAT | // Chip Select inactive after transfer
|
||||
// 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1
|
||||
// If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on
|
||||
// the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been
|
||||
// transferred in the shifter. This can imply for example, that the second data is sent twice.
|
||||
// COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay
|
||||
(csaat << 3) |
|
||||
/* Spi modes:
|
||||
Mode CPOL CPHA NCPHA
|
||||
0 0 0 1 clock normally low read on rising edge
|
||||
1 0 1 0 clock normally low read on falling edge
|
||||
2 1 0 1 clock normally high read on falling edge
|
||||
3 1 1 0 clock normally high read on rising edge
|
||||
However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI
|
||||
master mode the ATSAM7S512/256/128/64/321/32 does not sample the data
|
||||
(MISO) on the opposite edge where data clocks out (MOSI) but the same
|
||||
edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3
|
||||
shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and
|
||||
that the data changes sometime after the rising edge (about 2 ns). To
|
||||
be consistent with normal SPI operation, it is probably safe to say
|
||||
that the data changes on the falling edge and should be sampled on the
|
||||
rising edge. Therefore, it appears that NCPHA should be treated the
|
||||
same as CPHA. Thus:
|
||||
Mode CPOL CPHA NCPHA
|
||||
0 0 0 0 clock normally low read on rising edge
|
||||
1 0 1 1 clock normally low read on falling edge
|
||||
2 1 0 0 clock normally high read on falling edge
|
||||
3 1 1 1 clock normally high read on rising edge
|
||||
Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur.
|
||||
*/
|
||||
(ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge
|
||||
(cpol << 0); // Clock Polarity inactive state is logic 0
|
||||
|
||||
// read first, empty buffer
|
||||
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
|
||||
}
|
||||
|
||||
bool Flash_CheckBusy(uint32_t timeout) {
|
||||
WaitUS(WINBOND_WRITE_DELAY);
|
||||
StartCountUS();
|
||||
uint32_t _time = GetCountUS();
|
||||
|
||||
#ifndef AS_BOOTROM
|
||||
if (g_dbglevel > 3) Dbprintf("Checkbusy in...");
|
||||
#endif // AS_BOOTROM
|
||||
|
||||
do {
|
||||
if (!(Flash_ReadStat1() & BUSY)) {
|
||||
return false;
|
||||
}
|
||||
} while ((GetCountUS() - _time) < timeout);
|
||||
|
||||
if (timeout <= (GetCountUS() - _time)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// read state register 1
|
||||
uint8_t Flash_ReadStat1(void) {
|
||||
FlashSendByte(READSTAT1);
|
||||
return FlashSendLastByte(0xFF);
|
||||
}
|
||||
|
||||
// send one byte over SPI
|
||||
uint16_t FlashSendByte(uint32_t data) {
|
||||
|
||||
// wait until SPI is ready for transfer
|
||||
//if you are checking for incoming data returned then the TXEMPTY flag is redundant
|
||||
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
|
||||
|
||||
// send the data
|
||||
AT91C_BASE_SPI->SPI_TDR = data;
|
||||
|
||||
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){};
|
||||
|
||||
// wait receive transfer is complete
|
||||
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {};
|
||||
|
||||
// reading incoming data
|
||||
return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
|
||||
}
|
||||
|
||||
// send last byte over SPI
|
||||
uint16_t FlashSendLastByte(uint32_t data) {
|
||||
return FlashSendByte(data | AT91C_SPI_LASTXFER);
|
||||
}
|
184
common_arm/flashmem.h
Normal file
184
common_arm/flashmem.h
Normal file
|
@ -0,0 +1,184 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Borrowed initially from Arduino SPIFlash Library v.2.5.0
|
||||
// Copyright (C) 2015 by Prajwal Bhattaram.
|
||||
//
|
||||
// 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 3 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.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
// Common Instructions //
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
#ifndef __FLASHMEM_H
|
||||
#define __FLASHMEM_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
// Used Command
|
||||
#define ID 0x90
|
||||
#define MANID 0x90
|
||||
#define JEDECID 0x9F
|
||||
|
||||
#define READSTAT1 0x05
|
||||
#define READSTAT2 0x35
|
||||
#define WRITESTAT 0x01
|
||||
|
||||
#define WRITEDISABLE 0x04
|
||||
#define WRITEENABLE 0x06
|
||||
|
||||
#define READDATA 0x03
|
||||
#define FASTREAD 0x0B
|
||||
#define PAGEPROG 0x02
|
||||
|
||||
#define SECTORERASE 0x20
|
||||
#define BLOCK32ERASE 0x52
|
||||
#define BLOCK64ERASE 0xD8
|
||||
#define CHIPERASE 0xC7
|
||||
|
||||
#define UNIQUE_ID 0x4B
|
||||
|
||||
// Not used or not support command
|
||||
#define RELEASE 0xAB
|
||||
#define POWERDOWN 0xB9
|
||||
#define SUSPEND 0x75
|
||||
#define RESUME 0x7A
|
||||
|
||||
// Flash busy timeout: 20ms is the strict minimum when writing 256kb
|
||||
#define BUSY_TIMEOUT 200000L
|
||||
|
||||
#define WINBOND_MANID 0xEF
|
||||
#define WINBOND_DEVID 0x11
|
||||
#define PAGESIZE 0x100
|
||||
#define WINBOND_WRITE_DELAY 0x02
|
||||
|
||||
#define SPI_CLK 48000000
|
||||
|
||||
#define BUSY 0x01
|
||||
#define WRTEN 0x02
|
||||
#define SUS 0x40
|
||||
|
||||
#define DUMMYBYTE 0xEE
|
||||
#define NULLBYTE 0x00
|
||||
#define NULLINT 0x0000
|
||||
#define NO_CONTINUE 0x00
|
||||
#define PASS 0x01
|
||||
#define FAIL 0x00
|
||||
#define maxAddress capacity
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
// List of Error codes //
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
#define SUCCESS 0x00
|
||||
#define CALLBEGIN 0x01
|
||||
#define UNKNOWNCHIP 0x02
|
||||
#define UNKNOWNCAP 0x03
|
||||
#define CHIPBUSY 0x04
|
||||
#define OUTOFBOUNDS 0x05
|
||||
#define CANTENWRITE 0x06
|
||||
#define PREVWRITTEN 0x07
|
||||
#define LOWRAM 0x08
|
||||
#define NOSUSPEND 0x09
|
||||
#define UNKNOWNERROR 0xFF
|
||||
|
||||
// List of blocks
|
||||
#define MAX_BLOCKS 4
|
||||
#define MAX_SECTORS 16
|
||||
|
||||
//#define FLASH_BAUD 24000000
|
||||
#define FLASH_MINFAST 24000000 //33000000
|
||||
#define FLASH_BAUD MCK/2
|
||||
#define FLASH_FASTBAUD MCK
|
||||
#define FLASH_MINBAUD FLASH_FASTBAUD
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
bool FlashInit(void);
|
||||
void Flash_UniqueID(uint8_t *uid);
|
||||
void FlashStop(void);
|
||||
|
||||
void FlashSetup(uint32_t baudrate);
|
||||
bool Flash_CheckBusy(uint32_t timeout);
|
||||
uint8_t Flash_ReadStat1(void);
|
||||
uint16_t FlashSendByte(uint32_t data);
|
||||
uint16_t FlashSendLastByte(uint32_t data);
|
||||
|
||||
|
||||
#ifndef AS_BOOTROM
|
||||
// Bootrom does not require these functions.
|
||||
// Wrap in #ifndef to avoid accidental bloat of bootrom
|
||||
// Bootrom needs only enough to get uniqueID from flash.
|
||||
// It calls three functions. Full call trees listed:
|
||||
//
|
||||
// FlashInit()
|
||||
// |
|
||||
// \____ FlashSetup()
|
||||
// | \____ leaf
|
||||
// |
|
||||
// \____ StartTicks()
|
||||
// | \____ leaf
|
||||
// |
|
||||
// \____ Flash_CheckBusy() [*]
|
||||
// | \____ WaitUS()
|
||||
// | | \____ WaitTicks()
|
||||
// | | \____ leaf
|
||||
// | |
|
||||
// | \____ StartCountUS()
|
||||
// | | \____ leaf
|
||||
// | |
|
||||
// | \____ GetCountUS()
|
||||
// | | \____ leaf
|
||||
// | |
|
||||
// | \____ Flash_ReadStat1()
|
||||
// | \____ FlashSendByte()
|
||||
// | | \____ leaf
|
||||
// | |
|
||||
// | \____ FlashSendLastByte()
|
||||
// | \____ FlashSendByte()
|
||||
// | \____ leaf
|
||||
// |
|
||||
// \____ StopTicks()
|
||||
// \____ leaf
|
||||
//
|
||||
// Flash_UniqueID()
|
||||
// \____ FlashCheckBusy() (see FlashInit)
|
||||
// \____ FlashSendByteByte() (see FlashInit)
|
||||
// \____ FlashSendByteLastByte() (see FlashInit)
|
||||
//
|
||||
//
|
||||
// FlashStop() [*]
|
||||
|
||||
|
||||
|
||||
void FlashmemSetSpiBaudrate(uint32_t baudrate);
|
||||
bool Flash_WaitIdle(void);
|
||||
void Flash_TransferAdresse(uint32_t address);
|
||||
|
||||
|
||||
void Flash_WriteEnable(void);
|
||||
bool Flash_WipeMemoryPage(uint8_t page);
|
||||
bool Flash_WipeMemory(void);
|
||||
bool Flash_Erase4k(uint8_t block, uint8_t sector);
|
||||
//bool Flash_Erase32k(uint32_t address);
|
||||
bool Flash_Erase64k(uint8_t block);
|
||||
|
||||
uint8_t Flash_ReadID(void);
|
||||
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len);
|
||||
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len);
|
||||
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len);
|
||||
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len);
|
||||
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
|
||||
void Flashmem_print_status(void);
|
||||
void Flashmem_print_info(void);
|
||||
|
||||
#endif // #ifndef AS_BOOTROM
|
||||
|
||||
|
||||
#endif
|
325
common_arm/ticks.c
Normal file
325
common_arm/ticks.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Jonathan Westhues, Sept 2005
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// 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 3 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.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Timers, Clocks functions used in LF or Legic where you would need detailed time.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "ticks.h"
|
||||
|
||||
#include "proxmark3_arm.h"
|
||||
#ifndef AS_BOOTROM
|
||||
#include "dbprint.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef AS_BOOTROM
|
||||
|
||||
// timer counts in 666ns increments (32/48MHz), rounding applies
|
||||
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
|
||||
void SpinDelayUsPrecision(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 16) >> 5;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
|
||||
// 48 MHz / 32 gives 1.5 Mhz
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(5); // Channel Mode Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xFFFF; // Channel Period Register
|
||||
|
||||
uint16_t end = AT91C_BASE_PWMC_CH0->PWMC_CCNTR + ticks;
|
||||
if (end == 0) // AT91C_BASE_PWMC_CH0->PWMC_CCNTR is never == 0
|
||||
end++; // so we have to end++ to avoid inivity loop
|
||||
|
||||
for (;;) {
|
||||
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
|
||||
if (now == end)
|
||||
return;
|
||||
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
||||
// timer counts in 21.3us increments (1024/48MHz), rounding applies
|
||||
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
|
||||
void SpinDelayUs(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 512) >> 10;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
|
||||
// 48 MHz / 1024 gives 46.875 kHz
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register
|
||||
|
||||
uint16_t end = AT91C_BASE_PWMC_CH0->PWMC_CCNTR + ticks;
|
||||
if (end == 0) // AT91C_BASE_PWMC_CH0->PWMC_CCNTR is never == 0
|
||||
end++; // so we have to end++ to avoid inivity loop
|
||||
|
||||
for (;;) {
|
||||
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
|
||||
if (now == end)
|
||||
return;
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
|
||||
void SpinDelay(int ms) {
|
||||
if (ms > 1390) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf(_RED_("Error, SpinDelay called with %i > 1390"), ms);
|
||||
ms = 1390;
|
||||
}
|
||||
// convert to us and call microsecond delay function
|
||||
SpinDelayUs(ms * 1000);
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// timer lib
|
||||
// -------------------------------------------------------------------------
|
||||
// test procedure:
|
||||
//
|
||||
// ti = GetTickCount();
|
||||
// SpinDelay(1000);
|
||||
// ti = GetTickCount() - ti;
|
||||
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
|
||||
void StartTickCount(void) {
|
||||
// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
|
||||
// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
|
||||
while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available...
|
||||
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks
|
||||
// set RealTimeCounter divider to count at 1kHz, should be 32 if RC is exactly at 32kHz:
|
||||
AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((((MAINCK / 1000 * 16) + (mainf / 2)) / mainf) & AT91C_RTTC_RTPRES);
|
||||
// note: worst case precision is approx 2.5%
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current count.
|
||||
*/
|
||||
uint32_t RAMFUNC GetTickCount(void) {
|
||||
return AT91C_BASE_RTTC->RTTC_RTVR;
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) {
|
||||
uint32_t stop_ticks = AT91C_BASE_RTTC->RTTC_RTVR;
|
||||
if (stop_ticks >= start_ticks)
|
||||
return stop_ticks - start_ticks;
|
||||
return (UINT32_MAX - start_ticks) + stop_ticks;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Timer for iso14443 commands. Uses ssp_clk from FPGA
|
||||
// -------------------------------------------------------------------------
|
||||
void StartCountSspClk(void) {
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers
|
||||
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1
|
||||
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
|
||||
| AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0
|
||||
|
||||
// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1
|
||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
|
||||
| AT91C_TC_CPCSTOP // Stop clock on RC compare
|
||||
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
|
||||
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
|
||||
| AT91C_TC_ENETRG // Enable external trigger event
|
||||
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
|
||||
| AT91C_TC_WAVE // Waveform Mode
|
||||
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
|
||||
| AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare
|
||||
AT91C_BASE_TC1->TC_RC = 0x01; // RC Compare value = 0x01, pulse width to TC0
|
||||
|
||||
// use TC0 to count TIOA1 pulses
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1
|
||||
| AT91C_TC_WAVE // Waveform Mode
|
||||
| AT91C_TC_WAVESEL_UP // just count
|
||||
| AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare
|
||||
| AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare
|
||||
AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2
|
||||
AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow
|
||||
|
||||
// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2
|
||||
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0
|
||||
| AT91C_TC_WAVE // Waveform Mode
|
||||
| AT91C_TC_WAVESEL_UP; // just count
|
||||
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2
|
||||
|
||||
//
|
||||
// synchronize the counter with the ssp_frame signal.
|
||||
// Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present
|
||||
//
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame
|
||||
if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { // 16bit frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 4th ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 5th ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 6th ssp_clk after start of frame
|
||||
}
|
||||
|
||||
// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
|
||||
// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
|
||||
AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge)
|
||||
// at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
|
||||
// at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
|
||||
// whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
|
||||
// (just started with the transfer of the 4th Bit).
|
||||
|
||||
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows.
|
||||
// Therefore need to wait quite some time before we can use the counter.
|
||||
while (AT91C_BASE_TC2->TC_CV > 0);
|
||||
}
|
||||
void ResetSspClk(void) {
|
||||
//enable clock of timer and software trigger
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC2->TC_CV > 0);
|
||||
}
|
||||
uint32_t RAMFUNC GetCountSspClk(void) {
|
||||
uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
|
||||
if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2
|
||||
return (AT91C_BASE_TC2->TC_CV << 16);
|
||||
return tmp_count;
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start) {
|
||||
uint32_t stop = GetCountSspClk();
|
||||
if (stop >= start)
|
||||
return stop - start;
|
||||
return (UINT32_MAX - start) + stop;
|
||||
}
|
||||
|
||||
void WaitMS(uint32_t ms) {
|
||||
WaitTicks((ms & 0x1FFFFF) * 1500);
|
||||
}
|
||||
|
||||
#endif // #ifndef AS_BOOTROM
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// microseconds timer
|
||||
// -------------------------------------------------------------------------
|
||||
void StartCountUS(void) {
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
||||
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
|
||||
|
||||
// fast clock
|
||||
// tick=1.5mks
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
|
||||
AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
|
||||
AT91C_BASE_TC0->TC_RA = 1;
|
||||
AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
|
||||
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
|
||||
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
// Assert a sync signal. This sets all timers to 0 on next active clock edge
|
||||
AT91C_BASE_TCB->TCB_BCR = 1;
|
||||
|
||||
while (AT91C_BASE_TC1->TC_CV > 0);
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetCountUS(void) {
|
||||
//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
|
||||
// By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
|
||||
return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Timer for bitbanging, or LF stuff when you need a very precis timer
|
||||
// 1us = 1.5ticks
|
||||
// -------------------------------------------------------------------------
|
||||
void StartTicks(void) {
|
||||
// initialization of the timer
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
||||
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
|
||||
|
||||
// disable TC0 and TC1 for re-configuration
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
// first configure TC1 (higher, 0xFFFF0000) 16 bit counter
|
||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // just connect to TIOA0 from TC0
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
|
||||
|
||||
// second configure TC0 (lower, 0x0000FFFF) 16 bit counter
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
|
||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
|
||||
AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit)
|
||||
AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit)
|
||||
AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit)
|
||||
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
|
||||
AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
|
||||
|
||||
// synchronized startup procedure
|
||||
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
|
||||
while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared)
|
||||
|
||||
// return to zero
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC0->TC_CV > 0);
|
||||
}
|
||||
uint32_t GetTicks(void) {
|
||||
uint32_t hi, lo;
|
||||
|
||||
do {
|
||||
hi = AT91C_BASE_TC1->TC_CV;
|
||||
lo = AT91C_BASE_TC0->TC_CV;
|
||||
} while (hi != AT91C_BASE_TC1->TC_CV);
|
||||
|
||||
return (hi << 16) | lo;
|
||||
}
|
||||
|
||||
// Wait - Spindelay in ticks.
|
||||
// if called with a high number, this will trigger the WDT...
|
||||
void WaitTicks(uint32_t ticks) {
|
||||
if (ticks == 0) return;
|
||||
ticks += GetTicks();
|
||||
while (GetTicks() < ticks);
|
||||
}
|
||||
|
||||
// Wait / Spindelay in us (microseconds)
|
||||
// 1us = 1.5ticks.
|
||||
void WaitUS(uint32_t us) {
|
||||
WaitTicks((us & 0x3FFFFFFF) * 3 / 2);
|
||||
}
|
||||
|
||||
// stop clock
|
||||
void StopTicks(void) {
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
}
|
64
common_arm/ticks.h
Normal file
64
common_arm/ticks.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Jonathan Westhues, Aug 2005
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// 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 3 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.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Timers, Clocks functions used in LF or Legic where you would need detailed time.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __TICKS_H
|
||||
#define __TICKS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifndef GET_TICKS
|
||||
#define GET_TICKS GetTicks()
|
||||
#endif
|
||||
|
||||
void StartTicks(void);
|
||||
uint32_t GetTicks(void);
|
||||
void WaitUS(uint32_t us);
|
||||
void WaitTicks(uint32_t ticks);
|
||||
void StartCountUS(void);
|
||||
uint32_t RAMFUNC GetCountUS(void);
|
||||
void StopTicks(void);
|
||||
|
||||
|
||||
#ifndef AS_BOOTROM //////////////////////////////////////////////////////////////
|
||||
// Bootrom does not require these functions.
|
||||
// Wrap in #ifndef to avoid accidental bloat of bootrom
|
||||
|
||||
void SpinDelay(int ms);
|
||||
void SpinDelayUs(int us);
|
||||
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
|
||||
|
||||
void StartTickCount(void);
|
||||
uint32_t RAMFUNC GetTickCount(void);
|
||||
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks);
|
||||
|
||||
void ResetUSClock(void);
|
||||
void SpinDelayCountUs(uint32_t us);
|
||||
|
||||
void StartCountSspClk(void);
|
||||
void ResetSspClk(void);
|
||||
uint32_t RAMFUNC GetCountSspClk(void);
|
||||
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start);
|
||||
|
||||
void WaitMS(uint32_t ms);
|
||||
|
||||
#endif // #ifndef AS_BOOTROM
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -382,7 +382,6 @@ static const char StrSerialNumber[] = {
|
|||
// offset 18, length 32: 16x unicode chars (8-byte serial as hex characters)
|
||||
// ============================
|
||||
// total: 50 bytes
|
||||
|
||||
#define USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH 50
|
||||
char StrSerialNumber[] = {
|
||||
14, // Length is initially identical to non-unique version ... The length updated at boot, if unique serial is available
|
||||
|
@ -399,6 +398,7 @@ void usb_update_serial(uint64_t newSerialNumber) {
|
|||
}
|
||||
// run this only once per boot... even if it fails to find serial number
|
||||
configured = true;
|
||||
// reject serial number if all-zero or all-ones
|
||||
if ((newSerialNumber == 0x0000000000000000) || (newSerialNumber == 0xFFFFFFFFFFFFFFFF)) {
|
||||
return;
|
||||
}
|
||||
|
@ -407,10 +407,14 @@ void usb_update_serial(uint64_t newSerialNumber) {
|
|||
// Convert uniqueID's eight bytes to 16 unicode characters in the
|
||||
// descriptor and, finally, update the descriptor's length, which
|
||||
// causes the serial number to become visible.
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
uint8_t nibble = (uint8_t)((newSerialNumber >> (60 - (4*i))) & 0xFu);
|
||||
char c = nibble < 10 ? '0' + nibble : 'A' + (nibble-10);
|
||||
StrSerialNumber[18+(2*i)] = c; // [ 18, 20, 22, .., 46, 48 ]
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
// order of nibbles chosen to match display order from `hw status`
|
||||
uint8_t nibble1 = (newSerialNumber >> ((8*i) + 4)) & 0xFu; // bitmasks [0xF0, 0xF000, 0xF00000, ... 0xF000000000000000]
|
||||
uint8_t nibble2 = (newSerialNumber >> ((8*i) + 0)) & 0xFu; // bitmasks [0x0F, 0x0F00, 0x0F0000, ... 0x0F00000000000000]
|
||||
char c1 = nibble1 < 10 ? '0' + nibble1 : 'A' + (nibble1-10);
|
||||
char c2 = nibble2 < 10 ? '0' + nibble2 : 'A' + (nibble2-10);
|
||||
StrSerialNumber[46-(4*i)] = c1; // [ 46, 42, .., 22, 18 ]
|
||||
StrSerialNumber[48-(4*i)] = c2; // [ 48, 44, .., 24, 20 ]
|
||||
}
|
||||
StrSerialNumber[0] = USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue