Драйвер 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