mirror of
https://github.com/mist-devel/mist-firmware.git
synced 2026-01-13 15:17:43 +00:00
298 lines
6.4 KiB
C
298 lines
6.4 KiB
C
#include "spi.h"
|
|
#include "hardware.h"
|
|
|
|
void spi_init() {
|
|
// Enable the peripheral clock in the PMC
|
|
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI;
|
|
|
|
// Enable SPI interface
|
|
*AT91C_SPI_CR = AT91C_SPI_SPIEN;
|
|
|
|
// SPI Mode Register
|
|
*AT91C_SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | (0x0E << 16);
|
|
|
|
// SPI CS register
|
|
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (48 << 8) | (0x00 << 16) | (0x01 << 24);
|
|
|
|
// Configure pins for SPI use
|
|
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO;
|
|
}
|
|
|
|
RAMFUNC void spi_wait4xfer_end() {
|
|
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY));
|
|
|
|
/* Clear any data left in the receiver */
|
|
(void)*AT91C_SPI_RDR;
|
|
(void)*AT91C_SPI_RDR;
|
|
}
|
|
|
|
void EnableFpga()
|
|
{
|
|
*AT91C_PIOA_CODR = FPGA0; // clear output
|
|
}
|
|
|
|
void DisableFpga()
|
|
{
|
|
spi_wait4xfer_end();
|
|
*AT91C_PIOA_SODR = FPGA0; // set output
|
|
}
|
|
|
|
void EnableOsd()
|
|
{
|
|
*AT91C_PIOA_CODR = FPGA1; // clear output
|
|
}
|
|
|
|
void DisableOsd()
|
|
{
|
|
spi_wait4xfer_end();
|
|
*AT91C_PIOA_SODR = FPGA1; // set output
|
|
}
|
|
|
|
void EnableIO() {
|
|
*AT91C_PIOA_CODR = FPGA3; // clear output
|
|
}
|
|
|
|
void DisableIO() {
|
|
spi_wait4xfer_end();
|
|
*AT91C_PIOA_SODR = FPGA3; // set output
|
|
}
|
|
|
|
void EnableDMode() {
|
|
*AT91C_PIOA_CODR = FPGA2; // enable FPGA2 output
|
|
}
|
|
|
|
void DisableDMode() {
|
|
*AT91C_PIOA_SODR = FPGA2; // disable FPGA2 output
|
|
}
|
|
|
|
RAMFUNC void EnableCard() {
|
|
*AT91C_PIOA_CODR = MMC_SEL; // clear output (MMC chip select enabled)
|
|
}
|
|
|
|
RAMFUNC void DisableCard() {
|
|
spi_wait4xfer_end();
|
|
*AT91C_PIOA_SODR = MMC_SEL; // set output (MMC chip select disabled)
|
|
SPI(0xFF);
|
|
spi_wait4xfer_end();
|
|
}
|
|
|
|
void spi_block(unsigned short num) {
|
|
unsigned short i;
|
|
unsigned long t;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE)); // wait until transmiter buffer is empty
|
|
*AT91C_SPI_TDR = 0xFF; // write dummy spi data
|
|
}
|
|
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)); // wait for transfer end
|
|
t = *AT91C_SPI_RDR; // dummy read to empty receiver buffer for new data
|
|
}
|
|
|
|
RAMFUNC void spi_read(char *addr, uint16_t len) {
|
|
*AT91C_PIOA_SODR = AT91C_PA13_MOSI; // set GPIO output register
|
|
*AT91C_PIOA_OER = AT91C_PA13_MOSI; // GPIO pin as output
|
|
*AT91C_PIOA_PER = AT91C_PA13_MOSI; // enable GPIO function
|
|
|
|
// use SPI PDC (DMA transfer)
|
|
*AT91C_SPI_TPR = (unsigned long)addr;
|
|
*AT91C_SPI_TCR = len;
|
|
*AT91C_SPI_TNCR = 0;
|
|
*AT91C_SPI_RPR = (unsigned long)addr;
|
|
*AT91C_SPI_RCR = len;
|
|
*AT91C_SPI_RNCR = 0;
|
|
*AT91C_SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; // start DMA transfer
|
|
// wait for tranfer end
|
|
while ((*AT91C_SPI_SR & (AT91C_SPI_ENDTX | AT91C_SPI_ENDRX)) != (AT91C_SPI_ENDTX | AT91C_SPI_ENDRX));
|
|
*AT91C_SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; // disable transmitter and receiver
|
|
|
|
*AT91C_PIOA_PDR = AT91C_PA13_MOSI; // disable GPIO function
|
|
}
|
|
|
|
RAMFUNC void spi_block_read(char *addr) {
|
|
spi_read(addr, 512);
|
|
}
|
|
|
|
void spi_write(const char *addr, uint16_t len) {
|
|
// use SPI PDC (DMA transfer)
|
|
*AT91C_SPI_TPR = (unsigned long)addr;
|
|
*AT91C_SPI_TCR = len;
|
|
*AT91C_SPI_TNCR = 0;
|
|
*AT91C_SPI_RCR = 0;
|
|
*AT91C_SPI_PTCR = AT91C_PDC_TXTEN; // start DMA transfer
|
|
// wait for tranfer end
|
|
while (!(*AT91C_SPI_SR & AT91C_SPI_ENDTX));
|
|
*AT91C_SPI_PTCR = AT91C_PDC_TXTDIS; // disable transmitter
|
|
}
|
|
|
|
void spi_block_write(const char *addr) {
|
|
spi_write(addr, 512);
|
|
}
|
|
|
|
static unsigned char spi_speed;
|
|
|
|
void spi_slow() {
|
|
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_SLOW_CLK_VALUE << 8) | (2 << 24); // init clock 100-400 kHz
|
|
spi_speed = SPI_SLOW_CLK_VALUE;
|
|
}
|
|
|
|
void spi_fast() {
|
|
// set appropriate SPI speed for SD/SDHC card (max 25 Mhz)
|
|
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_SDC_CLK_VALUE << 8); // 24 MHz SPI clock
|
|
spi_speed = SPI_SDC_CLK_VALUE;
|
|
}
|
|
|
|
void spi_fast_mmc() {
|
|
// set appropriate SPI speed for MMC card (max 20Mhz)
|
|
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_MMC_CLK_VALUE << 8); // 16 MHz SPI clock
|
|
spi_speed = SPI_MMC_CLK_VALUE;
|
|
}
|
|
|
|
unsigned char spi_get_speed() {
|
|
return spi_speed;
|
|
}
|
|
|
|
void spi_set_speed(unsigned char speed) {
|
|
switch (speed) {
|
|
case SPI_SLOW_CLK_VALUE:
|
|
spi_slow();
|
|
break;
|
|
|
|
case SPI_SDC_CLK_VALUE:
|
|
spi_fast();
|
|
break;
|
|
|
|
default:
|
|
spi_fast_mmc();
|
|
}
|
|
}
|
|
|
|
/* generic helper */
|
|
unsigned char spi_in() {
|
|
return SPI(0);
|
|
}
|
|
|
|
void spi8(unsigned char parm) {
|
|
SPI(parm);
|
|
}
|
|
|
|
void spi16(unsigned short parm) {
|
|
SPI(parm >> 8);
|
|
SPI(parm >> 0);
|
|
}
|
|
|
|
void spi24(unsigned long parm) {
|
|
SPI(parm >> 16);
|
|
SPI(parm >> 8);
|
|
SPI(parm >> 0);
|
|
}
|
|
|
|
void spi32(unsigned long parm) {
|
|
SPI(parm >> 24);
|
|
SPI(parm >> 16);
|
|
SPI(parm >> 8);
|
|
SPI(parm >> 0);
|
|
}
|
|
|
|
// little endian: lsb first
|
|
void spi32le(unsigned long parm) {
|
|
SPI(parm >> 0);
|
|
SPI(parm >> 8);
|
|
SPI(parm >> 16);
|
|
SPI(parm >> 24);
|
|
}
|
|
|
|
void spi_n(unsigned char value, unsigned short cnt) {
|
|
while(cnt--)
|
|
SPI(value);
|
|
}
|
|
|
|
/* OSD related SPI functions */
|
|
void spi_osd_cmd_cont(unsigned char cmd) {
|
|
EnableOsd();
|
|
SPI(cmd);
|
|
}
|
|
|
|
void spi_osd_cmd(unsigned char cmd) {
|
|
spi_osd_cmd_cont(cmd);
|
|
DisableOsd();
|
|
}
|
|
|
|
void spi_osd_cmd8_cont(unsigned char cmd, unsigned char parm) {
|
|
EnableOsd();
|
|
SPI(cmd);
|
|
SPI(parm);
|
|
}
|
|
|
|
void spi_osd_cmd8(unsigned char cmd, unsigned char parm) {
|
|
spi_osd_cmd8_cont(cmd, parm);
|
|
DisableOsd();
|
|
}
|
|
|
|
void spi_osd_cmd32_cont(unsigned char cmd, unsigned long parm) {
|
|
EnableOsd();
|
|
SPI(cmd);
|
|
spi32(parm);
|
|
}
|
|
|
|
void spi_osd_cmd32(unsigned char cmd, unsigned long parm) {
|
|
spi_osd_cmd32_cont(cmd, parm);
|
|
DisableOsd();
|
|
}
|
|
|
|
void spi_osd_cmd32le_cont(unsigned char cmd, unsigned long parm) {
|
|
EnableOsd();
|
|
SPI(cmd);
|
|
spi32le(parm);
|
|
}
|
|
|
|
void spi_osd_cmd32le(unsigned char cmd, unsigned long parm) {
|
|
spi_osd_cmd32le_cont(cmd, parm);
|
|
DisableOsd();
|
|
}
|
|
|
|
/* User_io related SPI functions */
|
|
void spi_uio_cmd_cont(unsigned char cmd) {
|
|
EnableIO();
|
|
SPI(cmd);
|
|
}
|
|
|
|
void spi_uio_cmd(unsigned char cmd) {
|
|
spi_uio_cmd_cont(cmd);
|
|
DisableIO();
|
|
}
|
|
|
|
void spi_uio_cmd8_cont(unsigned char cmd, unsigned char parm) {
|
|
EnableIO();
|
|
SPI(cmd);
|
|
SPI(parm);
|
|
}
|
|
|
|
void spi_uio_cmd8(unsigned char cmd, unsigned char parm) {
|
|
spi_uio_cmd8_cont(cmd, parm);
|
|
DisableIO();
|
|
}
|
|
|
|
void spi_uio_cmd32(unsigned char cmd, unsigned long parm) {
|
|
EnableIO();
|
|
SPI(cmd);
|
|
SPI(parm);
|
|
SPI(parm>>8);
|
|
SPI(parm>>16);
|
|
SPI(parm>>24);
|
|
DisableIO();
|
|
}
|
|
|
|
void spi_uio_cmd64(unsigned char cmd, unsigned long long parm) {
|
|
EnableIO();
|
|
SPI(cmd);
|
|
SPI(parm);
|
|
SPI(parm>>8);
|
|
SPI(parm>>16);
|
|
SPI(parm>>24);
|
|
SPI(parm>>32);
|
|
SPI(parm>>40);
|
|
SPI(parm>>48);
|
|
SPI(parm>>56);
|
|
DisableIO();
|
|
}
|