1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-01-13 15:17:43 +00:00
2021-05-15 19:44:32 +02:00

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();
}