⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi.c

📁 Rtems drivers for mpc8260
💻 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 + -