Драйвер spi-baikal-t1.so для ЗОСРВ Нейтрино редакции 2020
Этот коммит содержится в:
Коммит
e9a13d9216
3
Makefile
Обычный файл
3
Makefile
Обычный файл
@ -0,0 +1,3 @@
|
||||
LIST=hardware
|
||||
EARLY_DIRS=i2c
|
||||
include recurse.mk
|
55
README.md
Обычный файл
55
README.md
Обычный файл
@ -0,0 +1,55 @@
|
||||
## Общая структура SPI драйвера
|
||||
|
||||
```
|
||||
┌───────────────────────────┐
|
||||
│ │
|
||||
│ SPI шина │
|
||||
│ │
|
||||
└─────────────▴─────────────┘
|
||||
│
|
||||
┌─────────────┴─────────────┐ ┌───────────────────────────┐
|
||||
│ │ │ │
|
||||
│ SPI-драйвер (spi-*) ◂────────┤ Менеджер spi-master │
|
||||
│ │ │ │
|
||||
└───────────────────────────┘ └───────────────────────────┘
|
||||
▲
|
||||
┌─────────────┴─────────────┐
|
||||
│ │
|
||||
│ Клиентское приложение │
|
||||
│ │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Дерево исходных кодов
|
||||
|
||||
```
|
||||
|- spi/
|
||||
| `- baikal-t1/ - Исходный код SPI-драйвера для Baikal-T1
|
||||
| |- Makefile - Правила сборки дерева исходников
|
||||
| `- common.mk - Параметры сборки драйверов
|
||||
|
|
||||
`- Makefile - Правила сборки дерева исходников
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Сборка драйвера
|
||||
|
||||
- Установить и настроить [комплект разработчика](https://help.kpda.ru/help/topic/ru.kpda.doc.dev_tools_ru/html/devkit/devkit.html) для [ЗОСРВ "Нейтрино" редакции 2020](https://help.kpda.ru/help/index.jsp).
|
||||
- Выполнить команду:
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Запуск драйвера
|
||||
|
||||
```
|
||||
spi-master -u1 -d baikal-t1 base=0x1f04e000,irq=0x128,gpiobase=0x1f044000,gpiocs=24 &
|
||||
```
|
||||
|
||||
|
2
spi/Makefile
Обычный файл
2
spi/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=BOARD
|
||||
include recurse.mk
|
8
spi/baikal-t1/Makefile
Обычный файл
8
spi/baikal-t1/Makefile
Обычный файл
@ -0,0 +1,8 @@
|
||||
LIST=CPU
|
||||
ifndef QRECURSE
|
||||
QRECURSE=recurse.mk
|
||||
ifdef QCONFIG
|
||||
QRDIR=$(dir $(QCONFIG))
|
||||
endif
|
||||
endif
|
||||
include $(QRDIR)$(QRECURSE)
|
264
spi/baikal-t1/baikal-t1-spi.h
Обычный файл
264
spi/baikal-t1/baikal-t1-spi.h
Обычный файл
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* (c) 2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*
|
||||
* (c) 2014 Baikal Electronics. Based on U-Boot code from Baikal Electronics.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board: Baikal-T1 CPC313
|
||||
* Interface: SPI
|
||||
* Contain control structures, wrapped i/o functions,
|
||||
* register's offsets and bitmasks
|
||||
*/
|
||||
|
||||
#ifndef _BAIKALSPI_H_INCLUDED
|
||||
#define _BAIKALSPI_H_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/slog.h>
|
||||
|
||||
#include <hw/inout.h>
|
||||
#include <hw/spi-master.h>
|
||||
|
||||
#include <mips/baikalt1_intr.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define BAIKAL_SPI_PRIORITY 21
|
||||
#define BAIKAL_SPI_EVENT 1
|
||||
|
||||
#define BAIKAL_SPI_BUS_FREQ 50000000 /* 50 MHz system clock */
|
||||
#define BAIKAL_SPI_SIZE 0x100
|
||||
#define BAIKAL_SPI_FIFO_LEN 64
|
||||
|
||||
#define BAIKAL_SPI1_BASE 0x1F04E000
|
||||
#define BAIKAL_SPI1_IRQ BT1_INTR_SPI0 /* 0x128 */
|
||||
#define BAIKAL_SPI2_BASE 0x1F04F000
|
||||
#define BAIKAL_SPI2_IRQ BT1_INTR_SPI1 /* 0x129 */
|
||||
|
||||
#define BAIKAL_GPIO_BASE 0x1F044000
|
||||
#define BAIKAL_GPIO_CS_PIN 24
|
||||
#define BAIKAL_GPIO_SIZE 0x78 /* Last 32bit reg. at offset 0x74 */
|
||||
#define GPIO_DR 0x0
|
||||
#define GPIO_DR_HIGH 0x1
|
||||
#define GPIO_DR_LOW 0x0
|
||||
#define GPIO_DDR 0x4
|
||||
#define GPIO_DDR_INPUT 0x0
|
||||
#define GPIO_DDR_OUTPUT 0x1
|
||||
|
||||
/* REGISTER ADDRESSES */
|
||||
#define SPI_CTRLR0 0x00 /* Control Register 0 */
|
||||
#define SPI_CTRLR1 0x04 /* Control Register 1 */
|
||||
#define SPI_SSIENR 0x08 /* SSI Enable Register */
|
||||
#define SPI_MWCR 0x0c /* Microwire Control Register. */
|
||||
#define SPI_SER 0x10 /* Slave Enable Register. */
|
||||
#define SPI_BAUDR 0x14 /* Baud Rate Select. */
|
||||
#define SPI_TXFTLR 0x18 /* Transmit FIFO Threshold Level. */
|
||||
#define SPI_RXFTLR 0x1c /* Receive FIFO Threshold level. */
|
||||
#define SPI_TXFLR 0x20 /* Transmit FIFO Level Register */
|
||||
#define SPI_RXFLR 0x24 /* Receive FIFO Level Register */
|
||||
#define SPI_SR 0x28 /* Status Register */
|
||||
#define SPI_IMR 0x2c /* Interrupt Mask Register */
|
||||
#define SPI_ISR 0x30 /* Interrupt Status Register */
|
||||
#define SPI_RISR 0x34 /* Raw Interrupt Status Register */
|
||||
#define SPI_TXOICR 0x38 /* Transmit FIFO Overflow Interrupt Clear Register */
|
||||
#define SPI_RXOICR 0x3c /* Receive FIFO Overflow Interrupt Clear Register */
|
||||
#define SPI_RXUICR 0x40 /* Receive FIFO Underflow Interrupt Clear Register */
|
||||
#define SPI_MSTICR 0x44 /* Multi-Master Interrupt Clear Register */
|
||||
#define SPI_ICR 0x48 /* Interrupt Clear Register */
|
||||
#define SPI_DMACR 0x4c /* DMA Control Register. */
|
||||
#define SPI_DMATDLR 0x50 /* DMA Transmit Data Level. */
|
||||
#define SPI_DMARDLR 0x54 /* DMA Receive Data Level. */
|
||||
#define SPI_IDR 0x58 /* Identification Register. */
|
||||
#define SPI_SSI_VERSION_ID 0x5c /* coreKit Version ID Register */
|
||||
#define SPI_DR0 0x60 /* A 16-bit read/write buffer for the transmit/receive FIFOs. */
|
||||
#define SPI_DR35 0xec /* A 16-bit read/write buffer for the transmit/receive FIFOs. */
|
||||
#define SPI_RX_SAMPLE_DLY 0xf0 /* RX Sample Delay. */
|
||||
#define SPI_RSVD_0 0xf4 /* RSVD_0 - Reserved address location */
|
||||
#define SPI_RSVD_1 0xf8 /* RSVD_1 - Reserved address location */
|
||||
#define SPI_RSVD_2 0xfc /* RSVD_2 - Reserved address location */
|
||||
|
||||
/* Bit fields in ISR, RISR, IMR */
|
||||
#define SPI_INT_TXEI (1 << 0)
|
||||
#define SPI_INT_TXOI (1 << 1)
|
||||
#define SPI_INT_RXUI (1 << 2)
|
||||
#define SPI_INT_RXOI (1 << 3)
|
||||
#define SPI_INT_RXFI (1 << 4)
|
||||
#define SPI_INT_MSTI (1 << 5)
|
||||
#define SPI_INT_MASK 0x3f /* Full Mask */
|
||||
|
||||
#define SPI_DISABLE 0x0
|
||||
#define SPI_ENABLE 0x1
|
||||
|
||||
#define BIT( x ) (1 << (x))
|
||||
|
||||
/* Bit fields in CTRLR0 */
|
||||
#define SPI_DFS_OFFSET 0
|
||||
#define SPI_DFS_8BIT 0x8
|
||||
#define SPI_DFS( x ) (((x) - 1) << SPI_DFS_OFFSET)
|
||||
|
||||
/* Frame Format */
|
||||
#define SPI_FRF_OFFSET 4
|
||||
#define SPI_FRF_SPI 0x0
|
||||
#define SPI_FRF_SSP 0x1
|
||||
#define SPI_FRF_MICROWIRE 0x2
|
||||
#define SPI_FRF_RESV 0x3
|
||||
#define SPI_FRF( x ) ((x) << SPI_FRF_OFFSET)
|
||||
|
||||
/* Serial Clock Phase. */
|
||||
#define SPI_SCPH_OFFSET 6
|
||||
#define SPI_SCPH_MIDDLE 0
|
||||
#define SPI_SCPH_START 1
|
||||
#define SPI_SCPH( x ) ((x) << SPI_SCPH_OFFSET)
|
||||
|
||||
/* Serial Clock Polarity. */
|
||||
#define SPI_SCPOL_OFFSET 7
|
||||
#define SPI_SCPOL_LOW 0
|
||||
#define SPI_SCPOL_HIGH 1
|
||||
#define SPI_SCPOL( x ) ((x) << SPI_SCPOL_OFFSET)
|
||||
|
||||
/* SPI Clock Mode */
|
||||
#define SPI_CPHA 0x01 /* clock phase */
|
||||
#define SPI_CPOL 0x02 /* clock polarity */
|
||||
#define SPI_MODE_OFFSET SPI_SCPH_OFFSET
|
||||
#define SPI_MODE_0 ( 0 | 0 )
|
||||
#define SPI_MODE_1 ( 0 | SPI_CPHA )
|
||||
#define SPI_MODE_2 ( SPI_CPOL | 0 )
|
||||
#define SPI_MODE_3 ( SPI_CPOL | SPI_CPHA)
|
||||
#define SPI_MODE( x ) ((x) << SPI_MODE_OFFSET)
|
||||
|
||||
/* Transfer mode bits */
|
||||
#define SPI_TMOD_OFFSET 8
|
||||
#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
|
||||
#define SPI_TMOD_TR 0x00 /* transmit and receive */
|
||||
#define SPI_TMOD_TO 0x01 /* transmit only */
|
||||
#define SPI_TMOD_RO 0x02 /* receive only */
|
||||
#define SPI_TMOD_EPROMREAD 0x03 /* EEPROM read */
|
||||
#define SPI_TMOD( x ) ((x) << SPI_TMOD_OFFSET)
|
||||
|
||||
|
||||
/* Slave output enable. */
|
||||
//#define SPI_SLV_OE_OFFSET 10
|
||||
//#define SPI_SLV_OE 1
|
||||
//#define SPI_SLV( x ) ((x) << SPI_SLV_OE_OFFSET)
|
||||
|
||||
#define SPI_SRL_OFFSET 11
|
||||
#define SPI_SRL( x ) ((x) << SPI_SRL_OFFSET)
|
||||
|
||||
//#define SPI_CFS_OFFSET 12
|
||||
/* End CTRLR0 */
|
||||
|
||||
|
||||
/* Bit fields in SR */
|
||||
#define SPI_SR_DCOL BIT( 6 )
|
||||
#define SPI_SR_TXE BIT( 5 )
|
||||
#define SPI_SR_RFF BIT( 4 )
|
||||
#define SPI_SR_RFNE BIT( 3 )
|
||||
#define SPI_SR_TFE BIT( 2 )
|
||||
#define SPI_SR_TFNF BIT( 1 )
|
||||
#define SPI_SR_BUSY BIT( 0 )
|
||||
|
||||
/* xfer errcode in interrupt mode */
|
||||
#define SPI_XFER_OK 0
|
||||
#define SPI_XFER_TIMEO 1
|
||||
#define SPI_XFER_FIFO 2
|
||||
|
||||
typedef struct {
|
||||
uint64_t pbase; /* the physical base address of GPIO port used as chip select */
|
||||
uintptr_t vbase; /* the virtual base address of GPIO port used as chip select */
|
||||
#define GPIOCS_EN (1 << 30) /* GPIO based chip selection is enabled */
|
||||
#define GPIOCS_CSHOLD (1 << 29) /* SPI_MODE_CSHOLD_HIGH is set by spi_setcfg */
|
||||
#define MSK_GPIO 0x0000001f /* get only the GPIO number used for chip selection */
|
||||
uint32_t gpio; /* combination of the GPIO number & flags mentioned previously */
|
||||
} gpio_cs_t;
|
||||
|
||||
typedef struct {
|
||||
SPIDEV spi; /* This has to be the first element */
|
||||
|
||||
uint64_t pbase;
|
||||
uintptr_t vbase;
|
||||
|
||||
uint32_t irq; /* interrupt vector to use in InterruptAttach() calls */
|
||||
int iid; /* 'id' returned from InterruptAttach() */
|
||||
int chid; /* 'id' returned from ChannelCreate() */
|
||||
int coid; /* 'id' returned from ConnectAttach() */
|
||||
|
||||
uint32_t clock;
|
||||
|
||||
volatile uint8_t *pbuf;
|
||||
int xlen, tlen, rlen;
|
||||
int dlen;
|
||||
int dtime; /* usec per data, for time out use */
|
||||
|
||||
uint32_t loopback; /* loopback mode */
|
||||
uint32_t poll; /* poll mode */
|
||||
gpio_cs_t gpiocs;
|
||||
struct sigevent spievent;
|
||||
} baikal_spi_dev_t;
|
||||
|
||||
|
||||
static inline uint32_t baikal_readl( baikal_spi_dev_t * dev, volatile uint32_t offset )
|
||||
{
|
||||
return inle32( dev->vbase + offset );
|
||||
}
|
||||
|
||||
static inline void baikal_writel( baikal_spi_dev_t * dev, uint32_t offset, uint32_t value )
|
||||
{
|
||||
outle32( dev->vbase + offset, value );
|
||||
}
|
||||
|
||||
/* Disable IRQ bits */
|
||||
static inline void spi_mask_intr( baikal_spi_dev_t * dev, uint32_t mask )
|
||||
{
|
||||
uint32_t new_mask;
|
||||
|
||||
new_mask = baikal_readl( dev, SPI_IMR ) & ~mask;
|
||||
baikal_writel( dev, SPI_IMR, new_mask );
|
||||
}
|
||||
|
||||
/* Enable IRQ bits */
|
||||
static inline void spi_umask_intr( baikal_spi_dev_t * dev, uint32_t mask )
|
||||
{
|
||||
uint32_t new_mask;
|
||||
|
||||
new_mask = baikal_readl( dev, SPI_IMR ) | mask;
|
||||
baikal_writel( dev, SPI_IMR, new_mask );
|
||||
}
|
||||
|
||||
static inline void baikal_spi_enable( baikal_spi_dev_t * dev, int enable )
|
||||
{
|
||||
baikal_writel( dev, SPI_SSIENR, (enable ? SPI_ENABLE : SPI_DISABLE));
|
||||
}
|
||||
|
||||
/*
|
||||
* This does disable the SPI controller, interrupts, and re-enable the
|
||||
* controller back. Transmit and receive FIFO buffers are cleared when the
|
||||
* device is disabled.
|
||||
*/
|
||||
static inline void baikal_spi_reset( baikal_spi_dev_t * dev )
|
||||
{
|
||||
baikal_spi_enable( dev, SPI_DISABLE );
|
||||
spi_mask_intr( dev, SPI_INT_MASK );
|
||||
baikal_spi_enable( dev, SPI_ENABLE );
|
||||
}
|
||||
|
||||
extern void *baikal_spi_init( void *hdl, char *options );
|
||||
extern void baikal_spi_dinit( void *hdl );
|
||||
extern int baikal_spi_setcfg( void *hdl, uint16_t device, spi_cfg_t *cfg );
|
||||
extern void *baikal_spi_xfer( void *hdl, uint32_t device, uint8_t *buf, int *len );
|
||||
|
||||
extern int baikal_spi_drvinfo( void *hdl, spi_drvinfo_t *info );
|
||||
extern int baikal_spi_devinfo( void *hdl, uint32_t device, spi_devinfo_t *info );
|
||||
|
||||
extern int baikal_spi_attach_intr( baikal_spi_dev_t *dev );
|
||||
extern int baikal_wait( baikal_spi_dev_t *dev, int len );
|
||||
|
||||
extern uint32_t baikal_spi_cfg( void *hdl, spi_cfg_t *cfg );
|
||||
|
||||
#endif
|
440
spi/baikal-t1/baikal-t1.c
Обычный файл
440
spi/baikal-t1/baikal-t1.c
Обычный файл
@ -0,0 +1,440 @@
|
||||
/*
|
||||
* (c) 2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*
|
||||
* (c) 2014 Baikal Electronics. Based on U-Boot code from Baikal Electronics.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board: Baikal-T1 CPC313
|
||||
* Interface: SPI
|
||||
* Initialize, configure and transfer
|
||||
*/
|
||||
|
||||
#include "baikal-t1-spi.h"
|
||||
|
||||
enum opt_index { BASE, IRQ, CLOCK, LOOPBACK, GPIOCSBASE, GPIOCS, POLL, END };
|
||||
|
||||
static char *baikal_opts[] = {
|
||||
[BASE] = "base", /* Base address for this SPI controller */
|
||||
[IRQ] = "irq", /* IRQ for this SPI intereface */
|
||||
[CLOCK] = "clock", /* SPI clock */
|
||||
[LOOPBACK] = "loopback", /* loopback interface for test purposes*/
|
||||
[GPIOCSBASE] = "gpiobase", /* gpio base address of bank of gpios used as
|
||||
* chipselects.
|
||||
* if SPI_MODE_CSHOLD_HIGH is to be used the corresponding
|
||||
* chipselect should be configured as gpio
|
||||
*/
|
||||
[GPIOCS] = "gpiocs", /* gpio pin number to be used as chipselect */
|
||||
[POLL] = "poll",
|
||||
[END] = NULL
|
||||
};
|
||||
|
||||
spi_funcs_t spi_drv_entry = {
|
||||
sizeof( spi_funcs_t ),
|
||||
baikal_spi_init, /* init() */
|
||||
baikal_spi_dinit, /* fini() */
|
||||
baikal_spi_drvinfo, /* drvinfo() */
|
||||
baikal_spi_devinfo, /* devinfo() */
|
||||
baikal_spi_setcfg, /* setcfg() */
|
||||
baikal_spi_xfer, /* xfer() */
|
||||
NULL /* dma_xfer() */
|
||||
};
|
||||
|
||||
static spi_devinfo_t devlist[1] = {
|
||||
{
|
||||
0x00, /* Device ID */
|
||||
"SPI-DEV0", /* Description */
|
||||
{
|
||||
SPI_MODE_CKPHASE_HALF |
|
||||
SPI_MODE_CSPOL_HIGH |
|
||||
8, /* data length 8 bit */
|
||||
1000000 /* Clock rate */
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static int baikal_spi_options( baikal_spi_dev_t *dev, char *optstring )
|
||||
{
|
||||
int opt, rc = 0;
|
||||
char *options, *freeptr, *c, *value;
|
||||
|
||||
if ( optstring == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
freeptr = options = strdup( optstring );
|
||||
|
||||
while ( options && *options != '\0' ) {
|
||||
c = options;
|
||||
if ( (opt = getsubopt( &options, baikal_opts, &value )) == -1 ) {
|
||||
goto error;
|
||||
}
|
||||
switch ( opt ) {
|
||||
case BASE:
|
||||
dev->pbase = strtoull( value, 0, 0 );
|
||||
continue;
|
||||
case IRQ:
|
||||
dev->irq = strtoul( value, 0, 0 );
|
||||
continue;
|
||||
case CLOCK:
|
||||
dev->clock = strtoul( value, 0, 0 );
|
||||
continue;
|
||||
case LOOPBACK:
|
||||
dev->loopback = value ? strtoul( value, 0, 0 ) : 1;
|
||||
continue;
|
||||
case GPIOCSBASE:
|
||||
dev->gpiocs.pbase = strtoul( value, 0, 0 );
|
||||
continue;
|
||||
case GPIOCS:
|
||||
dev->gpiocs.gpio = strtoull( value, 0, 0 ) | GPIOCS_EN;
|
||||
continue;
|
||||
case POLL:
|
||||
dev->poll = strtoul( value, 0, 0 );
|
||||
continue;
|
||||
}
|
||||
error:
|
||||
fprintf( stderr, "%s: unknown option %s", __FUNCTION__, c );
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
free( freeptr );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* baikal_spi_set_fifo_depth function set it to 0x3f again.
|
||||
* NOTE: fifo threshold after reset 0x3f.
|
||||
*/
|
||||
void baikal_spi_set_fifo_depth( baikal_spi_dev_t * dev ) {
|
||||
uint32_t fifo;
|
||||
|
||||
baikal_spi_enable( dev, SPI_DISABLE );
|
||||
|
||||
for ( fifo = 1; fifo <= BAIKAL_SPI_FIFO_LEN; fifo++ ) {
|
||||
baikal_writel( dev, SPI_TXFTLR, fifo );
|
||||
if ( fifo != baikal_readl( dev, SPI_TXFTLR ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
baikal_spi_enable( dev, SPI_ENABLE );
|
||||
fifo = baikal_readl( dev, SPI_TXFTLR );
|
||||
}
|
||||
|
||||
void baikal_gpio_cs_reset( baikal_spi_dev_t *dev )
|
||||
{
|
||||
uint32_t gpio_bit = BIT( dev->gpiocs.gpio & MSK_GPIO );
|
||||
uint32_t gpio = inle32( dev->gpiocs.vbase + GPIO_DR );
|
||||
|
||||
gpio |= gpio_bit;
|
||||
outle32( dev->gpiocs.vbase + GPIO_DR, gpio );
|
||||
outle32( dev->gpiocs.vbase + GPIO_DDR, gpio );
|
||||
|
||||
gpio &= ~gpio_bit;
|
||||
outle32( dev->gpiocs.vbase + GPIO_DR, gpio );
|
||||
outle32( dev->gpiocs.vbase + GPIO_DDR, gpio );
|
||||
}
|
||||
|
||||
void baikal_gpio_chip_select( baikal_spi_dev_t *dev, uint8_t dir, uint8_t level )
|
||||
{
|
||||
uint32_t gpio_bit = BIT( dev->gpiocs.gpio & MSK_GPIO );
|
||||
uint32_t gpio_dr = inle32( dev->gpiocs.vbase + GPIO_DR ); /* Data Register */
|
||||
uint32_t gpio_ddr = inle32( dev->gpiocs.vbase + GPIO_DDR ); /* Data Directrion Register */
|
||||
|
||||
if ( dir )
|
||||
gpio_ddr |= gpio_bit; /* Output Directrion */
|
||||
else
|
||||
gpio_ddr &= ~gpio_bit; /* Input Directrion */
|
||||
|
||||
/* GPIO Chip Select logic is inverted */
|
||||
if ( !level )
|
||||
gpio_dr |= gpio_bit;
|
||||
else
|
||||
gpio_dr &= ~gpio_bit;
|
||||
|
||||
outle32( dev->gpiocs.vbase + GPIO_DR, gpio_dr );
|
||||
outle32( dev->gpiocs.vbase + GPIO_DDR, gpio_ddr );
|
||||
}
|
||||
|
||||
void *baikal_spi_init( void *hdl, char *options )
|
||||
{
|
||||
baikal_spi_dev_t *dev;
|
||||
uintptr_t base;
|
||||
|
||||
dev = calloc( 1, sizeof( baikal_spi_dev_t ) );
|
||||
|
||||
if ( dev == NULL )
|
||||
return ( NULL );
|
||||
|
||||
dev->pbase = BAIKAL_SPI1_BASE;
|
||||
dev->irq = BAIKAL_SPI1_IRQ;
|
||||
dev->clock = BAIKAL_SPI_BUS_FREQ; /* 50 MHz */
|
||||
dev->poll = 0;
|
||||
/* GPIO Base Address and Pin Number set in baikal_spi_options() */
|
||||
// dev->gpiocs.pbase = BAIKAL_GPIO_BASE;
|
||||
// dev->gpiocs.gpio = 24 | GPIOCS_EN;
|
||||
|
||||
baikal_spi_options( dev, options );
|
||||
|
||||
if ( (base = mmap_device_io( BAIKAL_SPI_SIZE, dev->pbase )) == (uintptr_t)MAP_FAILED ) {
|
||||
/* error */
|
||||
goto fail0;
|
||||
}
|
||||
dev->vbase = base;
|
||||
|
||||
if ( dev->gpiocs.gpio & GPIOCS_EN ) {
|
||||
if ( (base = mmap_device_io( BAIKAL_GPIO_SIZE, dev->gpiocs.pbase )) == ( uintptr_t ) MAP_FAILED ) {
|
||||
/* error */
|
||||
goto fail1;
|
||||
}
|
||||
dev->gpiocs.vbase = base;
|
||||
}
|
||||
|
||||
baikal_spi_reset( dev );
|
||||
|
||||
// baikal_spi_set_fifo_depth( dev );
|
||||
|
||||
/* Set default data format */
|
||||
baikal_spi_setcfg( dev, 0, &devlist[0].cfg );
|
||||
|
||||
if ( dev->poll == 0 ) {
|
||||
/* Attach SPI interrupt */
|
||||
if ( baikal_spi_attach_intr( dev ) ) {
|
||||
goto fail2;
|
||||
}
|
||||
}
|
||||
|
||||
dev->spi.hdl = hdl;
|
||||
|
||||
return ( dev );
|
||||
|
||||
fail2:
|
||||
if ( dev->gpiocs.vbase ) {
|
||||
munmap_device_io( dev->gpiocs.vbase, BAIKAL_GPIO_SIZE );
|
||||
}
|
||||
fail1:
|
||||
munmap_device_io( dev->vbase, BAIKAL_SPI_SIZE );
|
||||
fail0:
|
||||
free( dev );
|
||||
return ( NULL );
|
||||
}
|
||||
|
||||
void baikal_spi_dinit( void *hdl )
|
||||
{
|
||||
baikal_spi_dev_t *dev = hdl;
|
||||
|
||||
/* Detach the interrupt */
|
||||
InterruptDetach( dev->iid );
|
||||
ConnectDetach( dev->coid );
|
||||
ChannelDestroy( dev->chid );
|
||||
|
||||
/* Disable SPI */
|
||||
baikal_spi_enable( dev, SPI_DISABLE );
|
||||
if ( dev->gpiocs.vbase != (uintptr_t)MAP_FAILED )
|
||||
munmap_device_io( dev->gpiocs.vbase, BAIKAL_GPIO_SIZE );
|
||||
|
||||
/* Unmap the register */
|
||||
munmap_device_io( dev->vbase, BAIKAL_SPI_SIZE );
|
||||
|
||||
free( hdl );
|
||||
}
|
||||
|
||||
int baikal_spi_drvinfo(void *hdl, spi_drvinfo_t *info)
|
||||
{
|
||||
info->version = ( SPI_VERSION_MAJOR << SPI_VERMAJOR_SHIFT ) |
|
||||
( SPI_VERSION_MINOR << SPI_VERMINOR_SHIFT ) |
|
||||
( SPI_REVISION << SPI_VERREV_SHIFT );
|
||||
strcpy( info->name, "Baikal-T1 SPI" );
|
||||
info->feature = 0;
|
||||
|
||||
return ( EOK );
|
||||
}
|
||||
|
||||
int baikal_spi_setcfg( void *hdl, uint16_t device, spi_cfg_t *cfg )
|
||||
{
|
||||
baikal_spi_dev_t *dev = hdl;
|
||||
uint32_t ctrl0 = 0;
|
||||
|
||||
/* We have only 4 Chip Select lines */
|
||||
if ( device > 0x4 )
|
||||
return ( EINVAL );
|
||||
|
||||
devlist[0].device = device;
|
||||
|
||||
memcpy( &devlist[0].cfg, cfg, sizeof( spi_cfg_t ) );
|
||||
|
||||
if ( (ctrl0 = baikal_spi_cfg( hdl, &devlist[0].cfg )) == 0 )
|
||||
return ( EINVAL );
|
||||
|
||||
baikal_spi_enable( dev, SPI_DISABLE ); /* Disable controller */
|
||||
baikal_writel( dev, SPI_CTRLR0, ctrl0 ); /* Write cfg */
|
||||
baikal_spi_enable( dev, SPI_ENABLE ); /* Enable controller */
|
||||
|
||||
/* NOTE: slave select (SS) polarity, 0 = active low, 1 = active high
|
||||
* NOTE: SCLK and SS polarity bit settings are different */
|
||||
if ( cfg->mode & SPI_MODE_CSHOLD_HIGH ) {
|
||||
baikal_writel( dev, SPI_SER, BIT( device ) );
|
||||
}
|
||||
else baikal_writel( dev, SPI_SER, 0x0 );
|
||||
|
||||
/* GPIO CS */
|
||||
if ( dev->gpiocs.vbase && ( dev->gpiocs.gpio & GPIOCS_EN ) )
|
||||
{
|
||||
if ( cfg->mode & SPI_MODE_CSHOLD_HIGH ) /* always keep the SSx assert */
|
||||
{
|
||||
dev->gpiocs.gpio |= GPIOCS_CSHOLD;
|
||||
if ( cfg->mode & SPI_MODE_CSPOL_HIGH )
|
||||
{
|
||||
dev->gpiocs.gpio |= SPI_MODE_CSPOL_HIGH;
|
||||
baikal_gpio_chip_select( dev, GPIO_DDR_OUTPUT, GPIO_DR_HIGH ); /* level high */
|
||||
}
|
||||
else {
|
||||
dev->gpiocs.gpio &= ~SPI_MODE_CSPOL_HIGH;
|
||||
baikal_gpio_chip_select( dev, GPIO_DDR_OUTPUT, GPIO_DR_LOW ); /* level low */
|
||||
}
|
||||
}
|
||||
else {
|
||||
dev->gpiocs.gpio &= ~GPIOCS_CSHOLD;
|
||||
if ( cfg->mode & SPI_MODE_CSPOL_HIGH )
|
||||
{
|
||||
dev->gpiocs.gpio |= SPI_MODE_CSPOL_HIGH;
|
||||
// baikal_gpio_chip_select( dev, GPIO_DDR_INPUT, GPIO_DR_LOW ); /* level low */
|
||||
}
|
||||
else {
|
||||
dev->gpiocs.gpio &= ~SPI_MODE_CSPOL_HIGH;
|
||||
// baikal_gpio_chip_select( dev, GPIO_DDR_INPUT, GPIO_DR_HIGH ); /* level high */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( EOK );
|
||||
}
|
||||
|
||||
int baikal_spi_devinfo( void *hdl, uint32_t device, spi_devinfo_t *info )
|
||||
{
|
||||
memcpy( info, &devlist[0], sizeof( spi_devinfo_t ) );
|
||||
return ( EOK );
|
||||
}
|
||||
|
||||
void *baikal_spi_xfer( void *hdl, uint32_t device, uint8_t *buf, int *len )
|
||||
{
|
||||
baikal_spi_dev_t *dev = hdl;
|
||||
uint32_t id;
|
||||
uint32_t clk_div;
|
||||
uint8_t level; /* chip select level high/low */
|
||||
|
||||
id = device & SPI_DEV_ID_MASK;
|
||||
if ( id > 4 ) {
|
||||
*len = -1;
|
||||
return buf;
|
||||
}
|
||||
|
||||
dev->tlen = 0;
|
||||
dev->rlen = 0;
|
||||
dev->xlen = *len;
|
||||
dev->pbuf = buf;
|
||||
dev->dlen = ((devlist[0].cfg.mode & 0xF) + 7) >> 3;
|
||||
dev->dtime = 1 + dev->dlen * 8 * 1000 * 1000 / devlist[0].cfg.clock_rate;
|
||||
|
||||
if ( dev->xlen < dev->dlen ) {
|
||||
*len = -1;
|
||||
fprintf( stderr, "%s: Unexpected exchange data length %d (word length is %d)\n", __FUNCTION__, dev->xlen, dev->dlen );
|
||||
}
|
||||
|
||||
baikal_spi_enable( dev, SPI_DISABLE );
|
||||
|
||||
/* Configure SPI Clock rate */
|
||||
clk_div = (dev->clock / devlist[0].cfg.clock_rate) + 1;
|
||||
clk_div &= 0xFFFE;
|
||||
|
||||
if ( clk_div != baikal_readl( dev, SPI_BAUDR ) )
|
||||
baikal_writel( dev, SPI_BAUDR, clk_div );
|
||||
|
||||
/* Enable Controller */
|
||||
baikal_spi_enable( dev, SPI_ENABLE );
|
||||
|
||||
/* CHIP SELECT */
|
||||
level = (dev->gpiocs.gpio & SPI_MODE_CSPOL_HIGH) ? GPIO_DR_HIGH : GPIO_DR_LOW;
|
||||
// if ( Chip Select Hold = Off )
|
||||
if ( 0 == (dev->gpiocs.gpio & GPIOCS_CSHOLD) ) {
|
||||
if ( dev->gpiocs.vbase && (dev->gpiocs.gpio & GPIOCS_EN) )
|
||||
baikal_gpio_chip_select( dev, GPIO_DDR_OUTPUT, level );
|
||||
}
|
||||
baikal_writel( dev, SPI_SER, BIT( device ) );
|
||||
|
||||
if ( dev->poll ) {
|
||||
/* poll mode */
|
||||
uint32_t data;
|
||||
while ( dev->rlen < dev->xlen ) {
|
||||
if ( dev->tlen < dev->xlen ) {
|
||||
switch ( dev->dlen ) {
|
||||
case 1:
|
||||
data = dev->pbuf[dev->tlen];
|
||||
break;
|
||||
case 2:
|
||||
data = *(uint16_t *)(&dev->pbuf[dev->tlen]);
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%s: Unsupported word length\n", __FUNCTION__ );
|
||||
*len = -1;
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
|
||||
baikal_writel( dev, SPI_DR0, data );
|
||||
dev->tlen += dev->dlen;
|
||||
}
|
||||
|
||||
if ( baikal_readl( dev, SPI_SR ) & SPI_SR_RFNE ) {
|
||||
data = baikal_readl( dev, SPI_DR0 );
|
||||
switch ( dev->dlen ) {
|
||||
case 1:
|
||||
dev->pbuf[dev->rlen] = data;
|
||||
break;
|
||||
case 2:
|
||||
*(uint16_t *)(&dev->pbuf[dev->rlen]) = data;
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%s: Unsupported word length\n", __FUNCTION__ );
|
||||
*len = -1;
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
dev->rlen += dev->dlen;
|
||||
}
|
||||
} /* while */
|
||||
} else {
|
||||
/* interrupt mode */
|
||||
spi_umask_intr( dev, SPI_INT_MASK );
|
||||
|
||||
switch ( baikal_wait( dev, dev->xlen ) ) {
|
||||
case SPI_XFER_OK:
|
||||
break;
|
||||
case SPI_XFER_FIFO:
|
||||
baikal_spi_reset( dev );
|
||||
fprintf( stderr, "%s: fifo overrun/underrun\n", __FUNCTION__ );
|
||||
dev->rlen = -1;
|
||||
break;
|
||||
case SPI_XFER_TIMEO:
|
||||
fprintf( stderr, "%s: timeout\n", __FUNCTION__ );
|
||||
dev->rlen = -1;
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%s: unknown error\n", __FUNCTION__ );
|
||||
dev->rlen = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*len = dev->rlen;
|
||||
|
||||
if ( 0 == ( dev->gpiocs.gpio & GPIOCS_CSHOLD ) ) {
|
||||
if ( dev->gpiocs.vbase && (dev->gpiocs.gpio & GPIOCS_EN) )
|
||||
baikal_gpio_chip_select( dev, GPIO_DDR_OUTPUT, !level );
|
||||
}
|
||||
baikal_writel( dev, SPI_SER, 0x0 );
|
||||
|
||||
fail:
|
||||
return buf;
|
||||
}
|
24
spi/baikal-t1/common.mk
Обычный файл
24
spi/baikal-t1/common.mk
Обычный файл
@ -0,0 +1,24 @@
|
||||
ifndef QCONFIG
|
||||
QCONFIG=qconfig.mk
|
||||
endif
|
||||
include $(QCONFIG)
|
||||
include $(MKFILES_ROOT)/qmacros.mk
|
||||
|
||||
NAME := spi-$(NAME)
|
||||
USEFILE=$(PROJECT_ROOT)/$(NAME).use
|
||||
EXTRA_SILENT_VARIANTS+=$(SECTION)
|
||||
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=
|
||||
endef
|
||||
|
||||
include $(PROJECT_ROOT)/pinfo.mk
|
||||
LDVFLAG_dll= -L.
|
||||
|
||||
#####AUTO-GENERATED by packaging script... do not checkin#####
|
||||
INSTALL_ROOT_nto = $(PROJECT_ROOT)/../../../../install
|
||||
USE_INSTALL_ROOT=1
|
||||
##############################################################
|
||||
|
||||
include $(MKFILES_ROOT)/qtargets.mk
|
||||
-include $(PROJECT_ROOT)/roots.mk
|
52
spi/baikal-t1/config.c
Обычный файл
52
spi/baikal-t1/config.c
Обычный файл
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* (c) 2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board: Baikal-T1 CPC313
|
||||
* Interface: SPI
|
||||
* Parse spi_cfg_t for interface configuring
|
||||
*/
|
||||
|
||||
#include "baikal-t1-spi.h"
|
||||
|
||||
uint32_t baikal_spi_cfg( void *hdl, spi_cfg_t *cfg )
|
||||
{
|
||||
baikal_spi_dev_t *dev = hdl;
|
||||
uint32_t spi_ctrl = 0;
|
||||
uint8_t len;
|
||||
|
||||
if ( cfg == NULL || dev == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = cfg->mode & SPI_MODE_CHAR_LEN_MASK;
|
||||
/* NOTE: len valid values [4..16] */
|
||||
if ( len < 4 || len > 16 )
|
||||
return 0;
|
||||
|
||||
/* if SPI_MODE_CSHOLD_HIGH is to be used the corresponding
|
||||
* chipselect should be configured as gpio */
|
||||
if ( (cfg->mode & SPI_MODE_CSHOLD_HIGH) && !dev->gpiocs.vbase )
|
||||
return 0;
|
||||
|
||||
if ( dev->loopback )
|
||||
spi_ctrl |= SPI_SRL( 1 ); /* Enable Test Mode */
|
||||
|
||||
spi_ctrl |= SPI_DFS( len );
|
||||
spi_ctrl |= SPI_FRF( SPI_FRF_SPI ); /* Frame Format: Motorolla SPI */
|
||||
|
||||
/* set SCLK polarity, CPOL: assume SPI_MODE_CKPOL_HIGH same as CPOL */
|
||||
if ( cfg->mode & SPI_MODE_CKPOL_HIGH )
|
||||
spi_ctrl |= SPI_SCPOL( SPI_SCPOL_HIGH ); /* set CPOL=1 */
|
||||
else
|
||||
spi_ctrl |= SPI_SCPOL( SPI_SCPOL_LOW ); /* set CPOL=0 */
|
||||
|
||||
/* set SCLK phase, CPHA: assume SPI_MODE_CKPHASE_HALF same as CPHA */
|
||||
if ( cfg->mode & SPI_MODE_CKPHASE_HALF )
|
||||
spi_ctrl |= SPI_SCPH( SPI_SCPH_MIDDLE ); /* set CPHA=0 */
|
||||
else
|
||||
spi_ctrl |= SPI_SCPH( SPI_SCPH_START ); /* set CPHA=1 */
|
||||
|
||||
return spi_ctrl;
|
||||
}
|
107
spi/baikal-t1/intr.c
Обычный файл
107
spi/baikal-t1/intr.c
Обычный файл
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* (c) 2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board: Baikal-T1 CPC313
|
||||
* Interface: SPI
|
||||
* Attach Interrupt and Interrupt handler functions
|
||||
*/
|
||||
|
||||
#include "baikal-t1-spi.h"
|
||||
|
||||
/*
|
||||
* We use the same buffer for transmit and receive
|
||||
* For exchange, that's exactly what we wanted
|
||||
* For Read, it doesn't matter what we write to SPI, so we are OK.
|
||||
* For transmit, the receive data is put at the buffer we just transmitted, we are still OK.
|
||||
*/
|
||||
static const struct sigevent *spi_intr( void *area, int id )
|
||||
{
|
||||
baikal_spi_dev_t *dev = area;
|
||||
uintptr_t base = dev->vbase;
|
||||
volatile uint32_t data;
|
||||
volatile uint32_t isr;
|
||||
|
||||
isr = inle32( base + SPI_ISR );
|
||||
|
||||
if ( isr & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI) ) {
|
||||
/* Disable Interrupts */
|
||||
outle32( base + SPI_IMR, 0x0 );
|
||||
/* Clear Interrupts */
|
||||
inle32( base + SPI_ICR );
|
||||
dev->spievent.sigev_value.sival_int = SPI_XFER_FIFO;
|
||||
return (&dev->spievent);
|
||||
}
|
||||
|
||||
if ( isr & SPI_INT_RXFI ) {
|
||||
data = inle32( base + SPI_DR0 );
|
||||
if ( dev->rlen <= dev->xlen ) {
|
||||
switch ( dev->dlen ) {
|
||||
case 1:
|
||||
dev->pbuf[dev->rlen] = data;
|
||||
break;
|
||||
case 2:
|
||||
*(uint16_t *)(&dev->pbuf[dev->rlen]) = data;
|
||||
break;
|
||||
}
|
||||
|
||||
dev->rlen += dev->dlen;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isr & SPI_INT_TXEI ) {
|
||||
/* More to transmit? */
|
||||
if ( dev->tlen < dev->xlen ) {
|
||||
switch ( dev->dlen ) {
|
||||
case 1:
|
||||
data = dev->pbuf[dev->tlen];
|
||||
break;
|
||||
case 2:
|
||||
data = *(uint16_t *)(&dev->pbuf[dev->tlen]);
|
||||
break;
|
||||
}
|
||||
|
||||
outle32( base + SPI_DR0, data );
|
||||
dev->tlen += dev->dlen;
|
||||
}
|
||||
}
|
||||
|
||||
if ( dev->rlen >= dev->xlen ) {
|
||||
/* Disable interrupt and return spievent */
|
||||
outle32( base + SPI_IMR, 0x0 );
|
||||
|
||||
dev->spievent.sigev_value.sival_int = SPI_XFER_OK;
|
||||
return (&dev->spievent);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int baikal_spi_attach_intr( baikal_spi_dev_t *dev )
|
||||
{
|
||||
if ( (dev->chid = ChannelCreate( _NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK )) == -1 )
|
||||
return (-1);
|
||||
|
||||
if ( (dev->coid = ConnectAttach( 0, 0, dev->chid, _NTO_SIDE_CHANNEL, 0 )) == -1 )
|
||||
goto fail0;
|
||||
|
||||
dev->spievent.sigev_notify = SIGEV_PULSE;
|
||||
dev->spievent.sigev_coid = dev->coid;
|
||||
dev->spievent.sigev_code = BAIKAL_SPI_EVENT;
|
||||
dev->spievent.sigev_priority = BAIKAL_SPI_PRIORITY;
|
||||
|
||||
/* Attach SPI interrupt */
|
||||
dev->iid = InterruptAttach( dev->irq, spi_intr, dev, 0, _NTO_INTR_FLAGS_TRK_MSK );
|
||||
|
||||
if ( dev->iid != -1 )
|
||||
return (0);
|
||||
|
||||
ConnectDetach( dev->coid );
|
||||
|
||||
fail0:
|
||||
ChannelDestroy( dev->chid );
|
||||
|
||||
return (-1);
|
||||
}
|
8
spi/baikal-t1/mips/Makefile
Обычный файл
8
spi/baikal-t1/mips/Makefile
Обычный файл
@ -0,0 +1,8 @@
|
||||
LIST=VARIANT
|
||||
ifndef QRECURSE
|
||||
QRECURSE=recurse.mk
|
||||
ifdef QCONFIG
|
||||
QRDIR=$(dir $(QCONFIG))
|
||||
endif
|
||||
endif
|
||||
include $(QRDIR)$(QRECURSE)
|
52
spi/baikal-t1/mips/baikalt1_intr.h
Обычный файл
52
spi/baikal-t1/mips/baikalt1_intr.h
Обычный файл
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* (c) 2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
/*
|
||||
* Baikal T1 interrupt number definitions
|
||||
*/
|
||||
|
||||
#ifndef __MIPS_BAIKALT1_INTR_H_INCLUDED
|
||||
#define __MIPS_BAIKALT1_INTR_H_INCLUDED
|
||||
|
||||
#include <mips/intr.h>
|
||||
|
||||
#define MIPS_BT1_INTR_CLASS (_NTO_INTR_CLASS_EXTERNAL + 0x100)
|
||||
#define MIPS_BT1_MSI_CLASS (_NTO_INTR_CLASS_EXTERNAL + 100)
|
||||
|
||||
#define BT1_INTR_IPI0 (MIPS_BT1_INTR_CLASS + 0)
|
||||
#define BT1_INTR_IPI15 (MIPS_BT1_INTR_CLASS + 15)
|
||||
#define BT1_INTR_APB (MIPS_BT1_INTR_CLASS + 16)
|
||||
#define BT1_INTR_WDT (MIPS_BT1_INTR_CLASS + 17)
|
||||
#define BT1_INTR_GPIO (MIPS_BT1_INTR_CLASS + 19)
|
||||
#define BT1_INTR_TMR0 (MIPS_BT1_INTR_CLASS + 24)
|
||||
#define BT1_INTR_TMR1 (MIPS_BT1_INTR_CLASS + 25)
|
||||
#define BT1_INTR_TMR2 (MIPS_BT1_INTR_CLASS + 26)
|
||||
#define BT1_INTR_PVT (MIPS_BT1_INTR_CLASS + 31)
|
||||
#define BT1_INTR_I2C0 (MIPS_BT1_INTR_CLASS + 32)
|
||||
#define BT1_INTR_I2C1 (MIPS_BT1_INTR_CLASS + 33)
|
||||
#define BT1_INTR_I2C2 (MIPS_BT1_INTR_CLASS + 34)
|
||||
#define BT1_INTR_SPI0 (MIPS_BT1_INTR_CLASS + 40)
|
||||
#define BT1_INTR_SPI1 (MIPS_BT1_INTR_CLASS + 41)
|
||||
#define BT1_INTR_UART0 (MIPS_BT1_INTR_CLASS + 48)
|
||||
#define BT1_INTR_UART1 (MIPS_BT1_INTR_CLASS + 49)
|
||||
#define BT1_INTR_DMAC (MIPS_BT1_INTR_CLASS + 56)
|
||||
#define BT1_INTR_SATA (MIPS_BT1_INTR_CLASS + 64)
|
||||
#define BT1_INTR_USB (MIPS_BT1_INTR_CLASS + 68)
|
||||
#define BT1_INTR_ETH_GMAC0 (MIPS_BT1_INTR_CLASS + 72)
|
||||
#define BT1_INTR_ETH_GMAC1 (MIPS_BT1_INTR_CLASS + 73)
|
||||
#define BT1_INTR_XGMAC (MIPS_BT1_INTR_CLASS + 74)
|
||||
#define BT1_INTR_XGMAC_TX0 (MIPS_BT1_INTR_CLASS + 75)
|
||||
#define BT1_INTR_XGMAC_TX1 (MIPS_BT1_INTR_CLASS + 76)
|
||||
#define BT1_INTR_XGMAC_RX0 (MIPS_BT1_INTR_CLASS + 77)
|
||||
#define BT1_INTR_XGMAC_RX1 (MIPS_BT1_INTR_CLASS + 78)
|
||||
#define BT1_INTR_XPCS (MIPS_BT1_INTR_CLASS + 79)
|
||||
#define BT1_INTR_PCIE_EDMA0 (MIPS_BT1_INTR_CLASS + 80)
|
||||
#define BT1_INTR_PCIE_MSI (MIPS_BT1_INTR_CLASS + 88)
|
||||
#define BT1_INTR_PCIE_AER (MIPS_BT1_INTR_CLASS + 89)
|
||||
#define BT1_INTR_PCIE_PME (MIPS_BT1_INTR_CLASS + 90)
|
||||
#define BT1_INTR_PCIE_HP (MIPS_BT1_INTR_CLASS + 91)
|
||||
#define BT1_INTR_PCIE_BW (MIPS_BT1_INTR_CLASS + 92)
|
||||
#define BT1_INTR_PCIE_L_REQ (MIPS_BT1_INTR_CLASS + 93)
|
||||
|
||||
#endif
|
1
spi/baikal-t1/mips/dll.le/Makefile
Обычный файл
1
spi/baikal-t1/mips/dll.le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../common.mk
|
41
spi/baikal-t1/module.tmpl
Обычный файл
41
spi/baikal-t1/module.tmpl
Обычный файл
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<module name="spi-baikal-t1">
|
||||
<type>Element</type>
|
||||
<classification>Driver</classification>
|
||||
|
||||
<description>
|
||||
<short>Baikal-T1 SPI Driver</short>
|
||||
<abstract>
|
||||
<![CDATA[The Serial Protocol Interface on the Baikal-T1 is protocol compatible
|
||||
with the standard Serial Protocol Interface (SPI). The Baikal-T1
|
||||
support for the SPI (spi-baikal) supports Full Duplex communication in
|
||||
Master mode. The SPI provides serial communications between the Baikal-T1
|
||||
CPU core and peripheral devices.]]>
|
||||
</abstract>
|
||||
</description>
|
||||
|
||||
<supports>
|
||||
<availability>
|
||||
<cpu isa="mips">
|
||||
<byteOrder>le</byteOrder>
|
||||
</cpu>
|
||||
</availability>
|
||||
</supports>
|
||||
|
||||
<source available="false">
|
||||
<location type="">.</location>
|
||||
</source>
|
||||
<GroupOwner>hw</GroupOwner>
|
||||
|
||||
<contents>
|
||||
<component id="spi-baikal-t1" generated="true">
|
||||
<location basedir="{cpu}/dll{.:endian}"
|
||||
runtime="true">spi-baikal-t1.so</location>
|
||||
</component>
|
||||
</contents>
|
||||
|
||||
<requires>
|
||||
<part build="true" location="lib/spi"/>
|
||||
<part build="false" location="hardware/spi"/>
|
||||
</requires>
|
||||
</module>
|
3
spi/baikal-t1/pinfo.mk
Обычный файл
3
spi/baikal-t1/pinfo.mk
Обычный файл
@ -0,0 +1,3 @@
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=Baikal-T1 SPI driver
|
||||
endef
|
19
spi/baikal-t1/spi-baikal-t1.use
Обычный файл
19
spi/baikal-t1/spi-baikal-t1.use
Обычный файл
@ -0,0 +1,19 @@
|
||||
%C Driver for Baikal-T1 SPI controller
|
||||
|
||||
Syntax:
|
||||
spi-master -d baikal-t1 [option[,option ...]] ... &
|
||||
|
||||
Options (to override autodetected defaults):
|
||||
|
||||
base=address Base address of SPI controller, default 0x1F04E000
|
||||
irq=num IRQ of the interface, default 0x128
|
||||
clock=num SPI clock, default 50MHz
|
||||
loopback=num Set internal loopback for test, default 0
|
||||
(loopback disabled)
|
||||
poll=num Enable poll mode, default 0 ( interrupt mode )
|
||||
gpiobase=address GPIO Base address for GPIO ChipSelect pin
|
||||
gpiocs=num GPIO pin number for CS pin
|
||||
|
||||
Example:
|
||||
# Start SPI driver with base address, IRQ and GPIO ChipSelect pin 24
|
||||
spi-master -d baikal-t1 base=0x1F04E000,irq=0x128,gpiobase=0x1F044000,gpiocs=24
|
34
spi/baikal-t1/wait.c
Обычный файл
34
spi/baikal-t1/wait.c
Обычный файл
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* (c) 2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board: Baikal-T1 CPC313
|
||||
* Interface: SPI
|
||||
* Wait event by Interrupt handler
|
||||
*/
|
||||
|
||||
#include "baikal-t1-spi.h"
|
||||
|
||||
int baikal_wait( baikal_spi_dev_t *dev, int len )
|
||||
{
|
||||
struct _pulse pulse;
|
||||
|
||||
while ( 1 ) {
|
||||
if ( len ) {
|
||||
uint64_t to = dev->dtime;
|
||||
to *= len * 1000 * 50; /* 50 times for time out */
|
||||
TimerTimeout( CLOCK_REALTIME, _NTO_TIMEOUT_RECEIVE, NULL, &to, NULL );
|
||||
}
|
||||
|
||||
if ( MsgReceivePulse( dev->chid, &pulse, sizeof( pulse ), NULL ) == -1 )
|
||||
return (SPI_XFER_TIMEO);
|
||||
|
||||
if ( pulse.code == BAIKAL_SPI_EVENT ){
|
||||
// fprintf( stderr, "pulse.value = %x\n", pulse.value );
|
||||
return (pulse.value.sival_int);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
Загрузка…
Ссылка в новой задаче
Block a user