📄 spi.c
字号:
/*$Id: spi.c,v 1.1 2002/03/07 16:38:11 rogers Exp $
*
* This file contains the functions for performing SPI I/O.
*
* Author: flpan
* Copyright (C) 2000 by UTStarcom, Inc.
*
*
* $Log: spi.c,v $
* Revision 1.1 2002/03/07 16:38:11 rogers
* First cut, includes serial EEPROM driver
*
*
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <tmacros.h>
#include <rtems.h>
#include <bsp.h>
#include <rtems/libio.h>
#include <mpc8260.h>
#include "cmntypes.h"
#include "spi.h"
volatile U8 Spi_Rx_Buf[4];
BOOL Fpga_Config_Flag = FALSE;
extern rtems_cpu_table Cpu_table;
extern void putbuf_raw(char *buf_p);
extern void putchar_raw(char ch);
void fpga_progress (U32 percent);
static volatile m8260BufferDescriptor_t *RxBd, *TxBd;
/*
* Dummy function
*/
void putbuf_raw(char *pStr)
{
}
rtems_status_code spi_initialize(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
volatile m8260SPIparms_t *spiparms;
/* Allocate buffer descriptors */
/* Rx buffer only one */
RxBd = M8260AllocateBufferDescriptors(1);
TxBd = M8260AllocateBufferDescriptors(1);
/* configure port D to enable SPICLK,SPIMOSI,SPIMISO pins */
m8260.iop[3].psor |= (SPI_CLK | SPI_OUTPUT | SPI_INPUT);
m8260.iop[3].ppar |= (SPI_CLK | SPI_OUTPUT | SPI_INPUT);
m8260.iop[3].pdir &= ~(SPI_CLK | SPI_OUTPUT | SPI_INPUT);
m8260.iop[3].podr &= ~(SPI_CLK | SPI_OUTPUT | SPI_INPUT);
/* Set initial output levels */
m8260.iop[1].pdat |= FPGA_PROGRAM | SPI_EEPROM_CS | SPI_EEPROM_HOLD |
SPI_EEPROM_WP;
/* configure PB25,26,27,29,30,31 as general purpose I/O pins */
m8260.iop[1].ppar &= ~(FPGA_PROGRAM | FPGA_INIT | FPGA_DONE |
SPI_EEPROM_CS | SPI_EEPROM_HOLD | SPI_EEPROM_WP);
/* configure PB25,26,27,31 as output */
m8260.iop[1].pdir |= FPGA_PROGRAM | SPI_EEPROM_CS | SPI_EEPROM_HOLD |
SPI_EEPROM_WP;
/* configure PB29,30 as input */
m8260.iop[1].pdir &= ~(FPGA_INIT | FPGA_DONE);
/* configure PB25,26,27,29,30,31 as actively driven */
m8260.iop[1].podr &= ~(FPGA_PROGRAM | FPGA_INIT | FPGA_DONE |
SPI_EEPROM_CS | SPI_EEPROM_HOLD | SPI_EEPROM_WP);
/* Setup pointer to SPI parameter RAM */
m8260.spi_base = (char *)&m8260.spip - (char *)&m8260;
/* set up SPI parameter RAM */
spiparms = (m8260SPIparms_t*)&m8260.spip;
spiparms->rbase = (char *)RxBd - (char *)&m8260;
spiparms->tbase = (char *)TxBd - (char *)&m8260;
spiparms->rfcr = M8260_RFCR_MOT | M8260_RFCR_GBL;
spiparms->tfcr = M8260_TFCR_MOT | M8260_TFCR_GBL;
/* every read cycle will return 3 bytes(cmd,adr,data) */
spiparms->mrblr = 4;
/* set up the RxBd */
RxBd->status = M8260_BD_EMPTY | M8260_BD_WRAP;
/* polling mode M8260_BD_INTERRUPT;*/
RxBd->length = 0;
RxBd->buffer = &Spi_Rx_Buf[0];
/* set up the TxBds */
TxBd->status = M8260_BD_WRAP;
/* clear any previous event */
m8260.spie = 0xFF;
/* using polling mode, disable all interrupts such as TXE,TXB,RXB */
m8260.spim = 0x00;
m8260.spmode = SPI_NORMAL_MODE ;
/* init Rx & Tx PARAMS */
M8260ExecuteRISC(M8260_CR_OP_INIT_RX_TX | M8260_CR_PGSB_SPI);
#if 1
if (fpga_configure() != SPI_SUCCESSFUL)
{
Fpga_Config_Flag = FALSE;
putbuf_raw(" failed\r\n");
}
else
{
Fpga_Config_Flag = TRUE;
putbuf_raw(" ok\r\n");
}
#endif
return SPI_SUCCESSFUL;
}/* end of m8260_spi_initialize() */
rtems_status_code spi_control(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg_p)
{
spi_ctrl_t *ctrl_p = (spi_ctrl_t *) arg_p;
spi_eeprom_parm_t *eeprom_parm;
rtems_status_code error_code;
/* check if major and minor numbers are valid */
if((major != SPI_MAJOR_NUMBER) || (minor != SPI_MINOR_NUMBER))
{
return RTEMS_INVALID_NUMBER;
}
switch(ctrl_p->opcode)
{
case SPI_CONFIG_FPGA:
error_code = fpga_configure();
break;
case SPI_EEPROM_XFER:
eeprom_parm = (spi_eeprom_parm_t *)ctrl_p->data_p;
m8260_spi_eeprom_mode(eeprom_parm->length);
error_code = spi_eeprom_xfer((void *)eeprom_parm);
m8260_spi_normal_mode();
break;
default:
error_code = SPI_FAILURE;
break;
}
return((error_code == SPI_SUCCESSFUL) ? RTEMS_SUCCESSFUL : error_code);
}
void m8260_spi_start()
{
m8260.spcom = M8260_SPCOM_STR;
}
void m8260_spi_fast_mode()
{
/* disable SPI */
m8260.spmode &= ~M8260_SPMODE_EN;
/* clear any previous event */
m8260.spie = 0xFF;
/* set up spmode */
m8260.spmode = SPI_FAST_MODE;
/* enable SPI */
m8260.spmode |= M8260_SPMODE_EN;
}
void m8260_spi_normal_mode()
{
/* disable SPI */
m8260.spmode &= ~(M8260_SPMODE_EN);
/* clear any previous event */
m8260.spie = 0xFF;
/* set up spmode */
m8260.spmode = SPI_NORMAL_MODE;
m8260.spip.mrblr = 4;
/* enable SPI */
m8260.spmode |= M8260_SPMODE_EN;
}
void m8260_spi_loop_normal()
{
/* disable SPI */
m8260.spmode &= ~M8260_SPMODE_EN;
/* clear any previous event */
m8260.spie = 0xFF;
/* set up spmode */
m8260.spmode &= ~M8260_SPMODE_LOOP;
/* enable SPI */
m8260.spmode |= M8260_SPMODE_EN;
}
void m8260_spi_loop_back()
{
/* disable SPI */
m8260.spmode &= ~(M8260_SPMODE_EN);
/* clear any previous event */
m8260.spie = 0xFF;
/* set up spmode */
m8260.spmode |= M8260_SPMODE_LOOP;
/* enable SPI */
m8260.spmode |= M8260_SPMODE_EN;
}
/*
* Real Time Clock functionality
*/
void m8260_spi_eeprom_mode(U16 mrbl)
{
/* disable SPI */
m8260.spmode &= ~(M8260_SPMODE_EN);
/* clear any previous event */
m8260.spie = 0xFF;
/* set up spmode */
m8260.spmode = SPI_EEPROM_MODE;
m8260.spip.mrblr = mrbl;
/* enable SPI */
m8260.spmode |= M8260_SPMODE_EN;
}
rtems_status_code spi_eeprom_xfer(void *arg_p)
{
spi_eeprom_parm_t *parm = (spi_eeprom_parm_t *)arg_p;
U32 level;
if(parm->tx_p == NULL || parm->rx_p == NULL || parm->length < 1)
return (U32)SPI_FAILURE;
TxBd->length = parm->length;
TxBd->buffer = parm->tx_p;
TxBd->status = M8260_BD_EMPTY | M8260_BD_WRAP |
M8260_BD_LAST;
RxBd->buffer = parm->rx_p;
/* active chip select signal */
m8260.iop[1].pdat &= ~SPI_EEPROM_CS;
/* start SPI transfer */
m8260.spcom = M8260_SPCOM_STR;
if(parm->length <= 4)
delay(50); /* Optimize short xfers, including WRITE */
else
rtems_task_wake_after(1); /* Wait 10ms */
/* deactive chip select signal */
m8260.iop[1].pdat |= SPI_EEPROM_CS;
_CPU_ISR_Disable(level);
RxBd->buffer = &Spi_Rx_Buf[0]; /* Set Rx buffer ptr back to normal */
if(RxBd->status & M8260_BD_EMPTY || TxBd->status & M8260_BD_READY)
{
_CPU_ISR_Enable(level);
/* clear any previous event */
m8260.spie = 0xFF;
return (U32)SPI_FAILURE;
}
/* reset the RxBd status */
RxBd->status = M8260_BD_EMPTY | M8260_BD_WRAP;
_CPU_ISR_Enable(level);
/* clear any previous event */
m8260.spie = 0xFF;
return (U32)SPI_SUCCESSFUL;
}
rtems_status_code fpga_configure()
{
S32 j = 0, length = 0, spi_fd = 0;
S32 read_len = 0;
S8 fpga_buf[SPI_PAGE_SIZE];
struct stat stat_info;
/* change SPI port to fast mode */
#if 0
m8260_spi_fast_mode();
#else
m8260_spi_normal_mode();
#endif
/* Open the spi file */
spi_fd = open (FPGA_FILE_NAME, O_RDONLY, 0755);
if (spi_fd < 0)
{
return SPI_FAILURE;
}
if (fstat (spi_fd, &stat_info) < 0)
{
close (spi_fd);
return SPI_FAILURE;
}
/* step1:hold FPGA /PROGRAM pin 1ms then turn to high, this will force
* FPGAs to clear its' configurtion memory. It is used to initiate
* a configuration cycle.
*/
m8260.iop[1].pdat &= ~FPGA_PROGRAM;
delay(1000);
m8260.iop[1].pdat |= FPGA_PROGRAM;
/* check FPGA /INIT signal */
j = 0;
while((m8260.iop[1].pdat & FPGA_INIT) == 0)
{
delay(1000);
j++;
if( j >= 5)
{
return(SPI_FAILURE);
}
}
/*step2: initiate load file from flash memory to FPGA */
length = stat_info.st_size;
#if 0
/* The first 16 bytes contains the magic number and the version
* So read beyond the header
*/
if (lseek (spi_fd, FLASH_HEADER_LEN, SEEK_SET) != FLASH_HEADER_LEN)
{
close (spi_fd);
return SPI_FAILURE;
}
/*step2: initiate load file from flash memory to FPGA */
length -= FLASH_HEADER_LEN;
#endif
j = 0;
putbuf_raw("program FPGA ");
while (length > 0)
{
read_len = read (spi_fd, fpga_buf, SPI_PAGE_SIZE);
if(length < SPI_PAGE_SIZE)
{
TxBd->length = read_len;
}
else
{
TxBd->length = SPI_PAGE_SIZE;
}
TxBd->buffer = (void *) fpga_buf;
TxBd->status = M8260_BD_EMPTY | M8260_BD_WRAP |
M8260_BD_LAST;
/* start SPI transfer */
m8260.spcom = M8260_SPCOM_STR;
/* check SPI transmit status */
j = 0;
while(TxBd->status & M8260_BD_EMPTY)
{
/*
* We cannot rtems_task_wake_after() here, since we are doing this
* before the kernel is completely up and running.
*/
delay(1000);
j++;
if(j > 100000)
{
m8260_spi_normal_mode();
return(SPI_FAILURE);
}
}/* end of second while */
/* adjust length */
if(length > SPI_PAGE_SIZE)
{
length -= SPI_PAGE_SIZE;
j++;
}
else
{
length = 0;
}
#if defined(SPI_DEBUG)
/*step3: check the FPGAs /INIT signal */
if((m8260.iop[1].pdat & FPGA_INIT) == 0)
{
m8260_spi_normal_mode();
close (spi_fd);
return SPI_FAILURE;
}
#endif
fpga_progress(100-length*100/stat_info.st_size);
}/* end of first while */
/*step3: check the FPGAs /INIT signal */
if((m8260.iop[1].pdat & FPGA_INIT) == 0)
{
m8260_spi_normal_mode();
close (spi_fd);
fpga_progress(100);
return SPI_FAILURE;
}
/* check the FPGAs DONE signal */
j = 0;
while((m8260.iop[1].pdat & FPGA_DONE) == 0)
{
delay(1000);
j++;
if(j >= 5)
{
m8260_spi_normal_mode();
printf("Didn't detect FPGA_DONE\n\r");
close (spi_fd);
return SPI_FAILURE;
}
}
/*step4: recover SPI port to normal mode */
m8260_spi_normal_mode();
/* reset the RxBd status */
RxBd->status = M8260_BD_EMPTY | M8260_BD_WRAP;
/* clear any previous event */
m8260.spie = 0xFF;
close (spi_fd);
return SPI_SUCCESSFUL;
}
void fpga_progress (U32 percent)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -