X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/ba8a80b30c4da36ef10854b53b06d9ff9acaca44..6949aca9fa0e37539fc277bac78e3d7a22117467:/armsrc/fpgaloader.c diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 88fdc4cf..04db41b3 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -21,27 +21,29 @@ void SetupSpi(int mode) // PA14 -> SPI_SPCK Serial Clock // Disable PIO control of the following pins, allows use by the SPI peripheral - PIO_DISABLE = (1 << GPIO_NCS0) | - (1 << GPIO_NCS2) | - (1 << GPIO_MISO) | - (1 << GPIO_MOSI) | - (1 << GPIO_SPCK); + AT91C_BASE_PIOA->PIO_PDR = + GPIO_NCS0 | + GPIO_NCS2 | + GPIO_MISO | + GPIO_MOSI | + GPIO_SPCK; - PIO_PERIPHERAL_A_SEL = (1 << GPIO_NCS0) | - (1 << GPIO_MISO) | - (1 << GPIO_MOSI) | - (1 << GPIO_SPCK); + AT91C_BASE_PIOA->PIO_ASR = + GPIO_NCS0 | + GPIO_MISO | + GPIO_MOSI | + GPIO_SPCK; - PIO_PERIPHERAL_B_SEL = (1 << GPIO_NCS2); + AT91C_BASE_PIOA->PIO_BSR = GPIO_NCS2; //enable the SPI Peripheral clock - PMC_PERIPHERAL_CLK_ENABLE = (1<PMC_PCER = (1<SPI_CR = AT91C_SPI_SPIEN; switch (mode) { case SPI_FPGA_MODE: - SPI_MODE = + AT91C_BASE_SPI->SPI_MR = ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) ( 0 << 7) | // Local Loopback Disabled @@ -49,7 +51,7 @@ void SetupSpi(int mode) ( 0 << 2) | // Chip selects connected directly to peripheral ( 0 << 1) | // Fixed Peripheral Select ( 1 << 0); // Master Mode - SPI_FOR_CHIPSEL_0 = + AT91C_BASE_SPI->SPI_CSR[0] = ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) ( 1 << 16) | // Delay Before SPCK (1 MCK period) ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud @@ -59,7 +61,7 @@ void SetupSpi(int mode) ( 0 << 0); // Clock Polarity inactive state is logic 0 break; case SPI_LCD_MODE: - SPI_MODE = + AT91C_BASE_SPI->SPI_MR = ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10) ( 0 << 7) | // Local Loopback Disabled @@ -67,7 +69,7 @@ void SetupSpi(int mode) ( 0 << 2) | // Chip selects connected directly to peripheral ( 0 << 1) | // Fixed Peripheral Select ( 1 << 0); // Master Mode - SPI_FOR_CHIPSEL_2 = + AT91C_BASE_SPI->SPI_CSR[2] = ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) ( 1 << 16) | // Delay Before SPCK (1 MCK period) ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud @@ -77,7 +79,7 @@ void SetupSpi(int mode) ( 0 << 0); // Clock Polarity inactive state is logic 0 break; default: // Disable SPI - SPI_CONTROL = SPI_CONTROL_DISABLE; + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; break; } } @@ -89,35 +91,36 @@ void SetupSpi(int mode) void FpgaSetupSsc(void) { // First configure the GPIOs, and get ourselves a clock. - PIO_PERIPHERAL_A_SEL = (1 << GPIO_SSC_FRAME) | - (1 << GPIO_SSC_DIN) | - (1 << GPIO_SSC_DOUT) | - (1 << GPIO_SSC_CLK); - PIO_DISABLE = (1 << GPIO_SSC_DOUT); + AT91C_BASE_PIOA->PIO_ASR = + GPIO_SSC_FRAME | + GPIO_SSC_DIN | + GPIO_SSC_DOUT | + GPIO_SSC_CLK; + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; - PMC_PERIPHERAL_CLK_ENABLE = (1 << PERIPH_SSC); + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC); // Now set up the SSC proper, starting from a known state. - SSC_CONTROL = SSC_CONTROL_RESET; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; // RX clock comes from TX clock, RX starts when TX starts, data changes // on RX clock rising edge, sampled on falling edge - SSC_RECEIVE_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); + AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync, start on positive-going edge of sync - SSC_RECEIVE_FRAME_MODE = SSC_FRAME_MODE_BITS_IN_WORD(8) | - SSC_FRAME_MODE_MSB_FIRST | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | + AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); // clock comes from TK pin, no clock output, outputs change on falling // edge of TK, start on rising edge of TF - SSC_TRANSMIT_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(2) | + AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing - SSC_TRANSMIT_FRAME_MODE = SSC_RECEIVE_FRAME_MODE; + AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR; - SSC_CONTROL = SSC_CONTROL_RX_ENABLE | SSC_CONTROL_TX_ENABLE; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; } //----------------------------------------------------------------------------- @@ -128,59 +131,110 @@ void FpgaSetupSsc(void) //----------------------------------------------------------------------------- void FpgaSetupSscDma(BYTE *buf, int len) { - PDC_RX_POINTER(SSC_BASE) = (DWORD)buf; - PDC_RX_COUNTER(SSC_BASE) = len; - PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)buf; - PDC_RX_NEXT_COUNTER(SSC_BASE) = len; - PDC_CONTROL(SSC_BASE) = PDC_RX_ENABLE; + AT91C_BASE_PDC_SSC->PDC_RPR = (DWORD)buf; + AT91C_BASE_PDC_SSC->PDC_RCR = len; + AT91C_BASE_PDC_SSC->PDC_RNPR = (DWORD)buf; + AT91C_BASE_PDC_SSC->PDC_RNCR = len; + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; } -// Download the fpga image starting at FpgaImage and with length FpgaImageLen DWORDs (e.g. 4 bytes) +static void DownloadFPGA_byte(unsigned char w) +{ +#define SEND_BIT(x) { if(w & (1<PIO_OER = GPIO_FPGA_ON; + AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON; + HIGH(GPIO_FPGA_ON); // ensure everything is powered on SpinDelay(50); LED_D_ON(); + // These pins are inputs + AT91C_BASE_PIOA->PIO_ODR = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; + // PIO controls the following pins + AT91C_BASE_PIOA->PIO_PER = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; + // Enable pull-ups + AT91C_BASE_PIOA->PIO_PPUER = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; + + // setup initial logic state HIGH(GPIO_FPGA_NPROGRAM); LOW(GPIO_FPGA_CCLK); LOW(GPIO_FPGA_DIN); - PIO_OUTPUT_ENABLE = (1 << GPIO_FPGA_NPROGRAM) | - (1 << GPIO_FPGA_CCLK) | - (1 << GPIO_FPGA_DIN); - SpinDelay(1); + // These pins are outputs + AT91C_BASE_PIOA->PIO_OER = + GPIO_FPGA_NPROGRAM | + GPIO_FPGA_CCLK | + GPIO_FPGA_DIN; + // enter FPGA configuration mode LOW(GPIO_FPGA_NPROGRAM); SpinDelay(50); HIGH(GPIO_FPGA_NPROGRAM); - for(i = 0; i < FpgaImageLen; i++) { - DWORD v = FpgaImage[i]; - unsigned char w; - for(j = 0; j < 4; j++) { - if(!bytereversal) - w = v >>(j*8); - else - w = v >>((3-j)*8); -#define SEND_BIT(x) { if(w & (1<PIO_PDSR & GPIO_FPGA_NINIT ) ) ) { + i--; + } + + // crude error indicator, leave both red LEDs on and return + if (i==0){ + LED_C_ON(); + LED_D_ON(); + return; + } + + if(bytereversal) { + /* This is only supported for DWORD aligned images */ + if( ((int)FpgaImage % sizeof(DWORD)) == 0 ) { + i=0; + while(FpgaImageLen-->0) + DownloadFPGA_byte(FpgaImage[(i++)^0x3]); + /* Explanation of the magic in the above line: + * i^0x3 inverts the lower two bits of the integer i, counting backwards + * for each 4 byte increment. The generated sequence of (i++)^3 is + * 3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 etc. pp. + */ } + } else { + while(FpgaImageLen-->0) + DownloadFPGA_byte(*FpgaImage++); } + // continue to clock FPGA until ready signal goes high + i=100000; + while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) { + HIGH(GPIO_FPGA_CCLK); + LOW(GPIO_FPGA_CCLK); + } + // crude error indicator, leave both red LEDs on and return + if (i==0){ + LED_C_ON(); + LED_D_ON(); + return; + } LED_D_OFF(); } @@ -191,7 +245,7 @@ static int bitparse_initialized; * 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01 * After that the format is 1 byte section type (ASCII character), 2 byte length * (big endian), bytes content. Except for section 'e' which has 4 bytes - * length. + * length. */ static const char _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01}; static int bitparse_init(void * start_address, void *end_address) @@ -208,7 +262,7 @@ static int bitparse_init(void * start_address, void *end_address) } } -int bitparse_find_section(char section_name, void **section_start, unsigned int *section_length) +int bitparse_find_section(char section_name, char **section_start, unsigned int *section_length) { char *pos = bitparse_headers_start; int result = 0; @@ -259,30 +313,30 @@ int bitparse_find_section(char section_name, void **section_start, unsigned int extern char _binary_fpga_bit_start, _binary_fpga_bit_end; void FpgaDownloadAndGo(void) { - /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start + /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start */ if(bitparse_init(&_binary_fpga_bit_start, &_binary_fpga_bit_end)) { /* Successfully initialized the .bit parser. Find the 'e' section and - * send its contents to the FPGA. + * send its contents to the FPGA. */ - void *bitstream_start; + char *bitstream_start; unsigned int bitstream_length; if(bitparse_find_section('e', &bitstream_start, &bitstream_length)) { - DownloadFPGA((DWORD *)bitstream_start, bitstream_length/4, 0); + DownloadFPGA(bitstream_start, bitstream_length, 0); return; /* All done */ } } /* Fallback for the old flash image format: Check for the magic marker 0xFFFFFFFF - * 0xAA995566 at address 0x2000. This is raw bitstream with a size of 336,768 bits + * 0xAA995566 at address 0x102000. This is raw bitstream with a size of 336,768 bits * = 10,524 DWORDs, stored as DWORDS e.g. little-endian in memory, but each DWORD * is still to be transmitted in MSBit first order. Set the invert flag to indicate * that the DownloadFPGA function should invert every 4 byte sequence when doing - * the bytewise download. + * the bytewise download. */ - if( *(DWORD*)0x2000 == 0xFFFFFFFF && *(DWORD*)0x2004 == 0xAA995566 ) - DownloadFPGA((DWORD *)0x2000, 10524, 1); + if( *(DWORD*)0x102000 == 0xFFFFFFFF && *(DWORD*)0x102004 == 0xAA995566 ) + DownloadFPGA((char*)0x102000, 10524*4, 1); } void FpgaGatherVersion(char *dst, int len) @@ -290,26 +344,26 @@ void FpgaGatherVersion(char *dst, int len) char *fpga_info; unsigned int fpga_info_len; dst[0] = 0; - if(!bitparse_find_section('e', (void**)&fpga_info, &fpga_info_len)) { + if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) { strncat(dst, "FPGA image: legacy image without version information", len-1); } else { strncat(dst, "FPGA image built", len-1); /* USB packets only have 48 bytes data payload, so be terse */ #if 0 - if(bitparse_find_section('a', (void**)&fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { strncat(dst, " from ", len-1); strncat(dst, fpga_info, len-1); } - if(bitparse_find_section('b', (void**)&fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { strncat(dst, " for ", len-1); strncat(dst, fpga_info, len-1); } #endif - if(bitparse_find_section('c', (void**)&fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + if(bitparse_find_section('c', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { strncat(dst, " on ", len-1); strncat(dst, fpga_info, len-1); } - if(bitparse_find_section('d', (void**)&fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + if(bitparse_find_section('d', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { strncat(dst, " at ", len-1); strncat(dst, fpga_info, len-1); } @@ -324,8 +378,8 @@ void FpgaGatherVersion(char *dst, int len) void FpgaSendCommand(WORD cmd, WORD v) { SetupSpi(SPI_FPGA_MODE); - while ((SPI_STATUS & SPI_STATUS_TX_EMPTY) == 0); // wait for the transfer to complete - SPI_TX_DATA = SPI_CONTROL_LAST_TRANSFER | cmd | v; // send the data + while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete + AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data } //----------------------------------------------------------------------------- // Write the FPGA setup word (that determines what mode the logic is in, read @@ -342,17 +396,19 @@ void FpgaWriteConfWord(BYTE v) // closable, but should only close one at a time. Not an FPGA thing, but // the samples from the ADC always flow through the FPGA. //----------------------------------------------------------------------------- -void SetAdcMuxFor(int whichGpio) +void SetAdcMuxFor(DWORD whichGpio) { - PIO_OUTPUT_ENABLE = (1 << GPIO_MUXSEL_HIPKD) | - (1 << GPIO_MUXSEL_LOPKD) | - (1 << GPIO_MUXSEL_LORAW) | - (1 << GPIO_MUXSEL_HIRAW); - - PIO_ENABLE = (1 << GPIO_MUXSEL_HIPKD) | - (1 << GPIO_MUXSEL_LOPKD) | - (1 << GPIO_MUXSEL_LORAW) | - (1 << GPIO_MUXSEL_HIRAW); + AT91C_BASE_PIOA->PIO_OER = + GPIO_MUXSEL_HIPKD | + GPIO_MUXSEL_LOPKD | + GPIO_MUXSEL_LORAW | + GPIO_MUXSEL_HIRAW; + + AT91C_BASE_PIOA->PIO_PER = + GPIO_MUXSEL_HIPKD | + GPIO_MUXSEL_LOPKD | + GPIO_MUXSEL_LORAW | + GPIO_MUXSEL_HIRAW; LOW(GPIO_MUXSEL_HIPKD); LOW(GPIO_MUXSEL_HIRAW);