initial commit

This commit is contained in:
Tautvydas Belgeras 2018-06-05 16:16:17 +03:00
commit 60a7afcc83
2528 changed files with 1001987 additions and 0 deletions

View file

@ -0,0 +1,896 @@
/*
* Routines to access hardware
*
* Copyright (c) 2015 Realtek Semiconductor Corp.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "device.h"
#include "rtl8710b_gspi_host.h"
#include "rtl8710b_inic.h"
#include "spi_api.h"
#include "spi_ex_api.h"
#include "gpio_api.h"
#include "gpio_irq_api.h"
#include "osdep_service.h"
#define CONFIG_GSPI_SLAVE 0
#define CONFIG_USE_INTERRUPT 1
#define PACK_SIZE 2048
#if !CONFIG_GSPI_SLAVE
/*host endian configuration
little-endian (1)
big-endan (0)
*/
#define CONFIG_HOST_ENDIAN 1
// SPI0
#define SPI0_MOSI PA_23
#define SPI0_MISO PA_22
#define SPI0_SCLK PA_18
#define SPI0_CS PA_19 // This pin is redundant
#if CONFIG_USE_INTERRUPT
#define GPIO_INT PA_27 // gspi external interrupt
#endif
#define GPIO_CS PA_28
#define SPI0_FREQUENCY (62500000/6)
static spi_t spi0_master;
static gpio_irq_t gpio_int;
static gpio_t gpio_cs;
typedef enum {
READ_REG = 0,
WRITE_REG
}_reg_ops;
// GSPI configuration (big endian recommended)
#define GSPI_CONFIG SPI_LITTLE_ENDIAN_32
// SPI master configuration
#define SPI_BITS 8 // Ameba SPI support 8bits and 16bits mode
struct spi_more_data {
unsigned long more_data;
unsigned long len;
};
#define SLAVE_SELECT() gpio_write(&gpio_cs, 0)
#define SLAVE_DESELECT() gpio_write(&gpio_cs, 1)
#define SPI_DUMMY 0xFF
// spi interrupt semaphore
_sema pspiIrqSemaphore;
// spi bus busy
_mutex SPIbusbusy;
volatile bool txDone = FALSE;
volatile bool rxDone = FALSE;
volatile bool txbusIdle = FALSE;
#define AGG_SIZE 5000
#define MAX_DUMMY_LEN 3
#define BUFFER_LEN GSPI_CMD_LEN+SIZE_RX_DESC+PACK_SIZE+8+MAX_DUMMY_LEN // GSPI_CMD + TX_DEC + DATA + GSPI_STATUS
unsigned char TX_DATA[PACK_SIZE];
unsigned char RX_DATA[PACK_SIZE+SIZE_RX_DESC]; // extra 100 byte for SDIO header
u32 rx_done=0;
unsigned char TX_BUFFER[BUFFER_LEN];
unsigned char RX_BUFFER[BUFFER_LEN];
#endif
#define TASK_STACK_SIZE 2048
#define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
#if CONFIG_GSPI_SLAVE
#include "spdio_api.h"
struct spdio_t spdio_dev;
#define SPDIO_TX_BD_NUM 6 // n*2, must be rounded to 2
#define SPDIO_RX_BD_NUM 6 //
#define SPDIO_RX_BUFSZ PACK_SIZE+64 //n*64, must be rounded to 64, extra 64 for TX descriptor
#define CONFIG_RX_BUFFER_REUSE 1
/*
* param: pdata, package
*/
char ex_gspi_tx(u8 *pdata, u16 size, u8 type){
static int rx_cnt = 0;
// LOOPBACK
printf("receive package, size = %d (cnt = %d) heap=%d\n", size, ++rx_cnt, xPortGetFreeHeapSize());
struct spdio_buf_t *tx_buf = (struct spdio_buf_t *)rtw_malloc(sizeof(struct spdio_buf_t));
if(!tx_buf)
return FAIL;
tx_buf->buf_allocated = (u32)rtw_malloc(size + SPDIO_DMA_ALIGN_4);
if(!tx_buf->buf_allocated)
{
rtw_mfree((u8 *)tx_buf, sizeof(struct spdio_buf_t));
return FAIL;
}
tx_buf->size_allocated = size + SPDIO_DMA_ALIGN_4;
tx_buf->buf_addr = (u32)N_BYTE_ALIGMENT((u32)(tx_buf->buf_allocated), SPDIO_DMA_ALIGN_4);
//printf("buf_addr = %x\n", tx_buf->buf_addr);
// copy data
memcpy((void*)tx_buf->buf_addr, pdata, size);
tx_buf->buf_size = size;
tx_buf->type = SPDIO_RX_DATA_USER; // you can define your own data type in spdio_rx_data_t and spdio_tx_data_t
// loopback
spdio_tx(&spdio_dev, tx_buf);
return SUCCESS;
}
/*spdio rx done callback (HOST->Device), manage your package and buffer*/
char ex_gspi_rx_done_cb(void *priv, void *pbuf, u8 *pdata, u16 size, u8 type){
struct spdio_t *obj = (struct spdio_t *)priv;
struct spdio_buf_t* rx_buf = (struct spdio_buf_t*)pbuf;
//2 handle package received
ex_gspi_tx(pdata, size, type);
#if !CONFIG_RX_BUFFER_REUSE
// manage rx_buf here
rtw_mfree((char *)rx_buf->buf_allocated, rx_buf->size_allocated);
//2 assign new buffer to RX
rx_buf->buf_allocated = (u32)rtw_malloc(obj->rx_bd_bufsz + SPDIO_DMA_ALIGN_4);
rx_buf->size_allocated = obj->rx_bd_bufsz + SPDIO_DMA_ALIGN_4;
// this buffer must be 4 byte alignment
rx_buf->buf_addr = (u32)N_BYTE_ALIGMENT((u32)(rx_buf->buf_allocated), SPDIO_DMA_ALIGN_4);
#endif
return SUCCESS;
}
/*spdio tx done callback(Device->HOST), manage buffer*/
// this API will be called after package have been read by HOST
char ex_gspi_tx_done_cb(void *priv, void *pbuf){
struct spdio_buf_t* tx_buf = (struct spdio_buf_t*)pbuf;
rtw_mfree((u8 *)tx_buf->buf_allocated, tx_buf->size_allocated);
rtw_mfree((u8 *)tx_buf, sizeof(struct spdio_buf_t));
return SUCCESS;
}
#else
int spi_transfer(uint8_t* buf, uint32_t buf_len)
{
int i = 0;
int ret = 0;
rtw_mutex_get(&SPIbusbusy);
SLAVE_SELECT();
txbusIdle = FALSE; // ensure TX done
rxDone = FALSE; // ensure RX done
if(spi_master_write_read_stream(&spi0_master, buf, buf, buf_len)!=0x00){
ret = -1;
}else{
ret = 0;
while((!txbusIdle) || (!rxDone)){
wait_us(20);
if (++i > 2000) {
DBG_8195A("SPI write and read Timeout...\r\n");
ret = -1;
break;
}
}
}
/* Chip Select Pull High */
SLAVE_DESELECT();
rtw_mutex_put(&SPIbusbusy);
return ret;
}
static int addr_convert(u32 addr)
{
u32 domain_id = 0 ;
u32 temp_addr = addr&0xffff0000;
switch (temp_addr) {
case SPI_LOCAL_OFFSET:
domain_id = SPI_LOCAL_DOMAIN;
break;
case SPI_TX_FIFO_OFFSET:
domain_id = SPI_TXFIFO_DOMAIN;
break;
case SPI_RX_FIFO_OFFSET:
domain_id = SPI_RXFIFO_DOMAIN;
break;
default:
break;
}
return domain_id;
}
static inline u32 DWORD_endian_reverse(u32 src, _gspi_conf_t gspi_conf)
{
u32 temp = 0;
switch(gspi_conf){
#if CONFIG_HOST_ENDIAN /*host little-endian*/
case SPI_LITTLE_ENDIAN_16:
temp = (((src&0x000000ff)<<8)|((src&0x0000ff00)>>8)|
((src&0x00ff0000)<<8)|((src&0xff000000)>>8));
break;
case SPI_LITTLE_ENDIAN_32:
temp = (((src&0x000000ff)<<24)|((src&0x0000ff00)<<8)|
((src&0x00ff0000)>>8)|((src&0xff000000)>>24));
break;
case SPI_BIG_ENDIAN_16:
case SPI_BIG_ENDIAN_32:
temp = src;
break;
#else /*host big-endian*/
case SPI_LITTLE_ENDIAN_16:
temp = (((src&0x0000ffff)<<16)|((src&0xffff0000)>>16);
break;
case SPI_LITTLE_ENDIAN_32:
temp = src;
break;
case SPI_BIG_ENDIAN_16:
case SPI_BIG_ENDIAN_32:
temp = (((src&0x000000ff)<<24)|((src&0x0000ff00)<<8)|
((src&0x00ff0000)>>8)|((src&0xff000000)>>24));
break;
#endif
}
return temp;
}
/*
* src buffer bit reorder
*/
static void buf_endian_reverse(u8* src, u32 len, u8* dummy_bytes, _gspi_conf_t gspi_conf)
{
u32 *buf = (u32*)src;
u16 count = len/4;
u16 remain = len%4;
int i = 0;
if(remain)
count ++;
for(i = 0;i < count; i++){
buf[i] = DWORD_endian_reverse(buf[i], gspi_conf);
}
if(remain)
*dummy_bytes = 4 - remain;
}
int gspi_read_write_reg(_reg_ops ops_type, u32 addr, char * buf, int len,_gspi_conf_t gspi_conf)
{
int fun = 1, domain_id = 0x0; //LOCAL
unsigned int cmd = 0 ;
int byte_en = 0 ;//,i = 0 ;
int ret = 0;
unsigned char status[GSPI_STATUS_LEN] = {0};
unsigned int data_tmp = 0;
u32 spi_buf[4] = {0};
if (len!=1 && len!=2 && len != 4) {
return -1;
}
domain_id = addr_convert(addr);
addr &= 0x7fff;
len &= 0xff;
if (ops_type == WRITE_REG) //write register
{
int remainder = addr % 4;
u32 val32 = *(u32 *)buf;
switch(len) {
case 1:
byte_en = (0x1 << remainder);
data_tmp = (val32& 0xff)<< (remainder*8);
break;
case 2:
byte_en = (0x3 << remainder);
data_tmp = (val32 & 0xffff)<< (remainder*8);
break;
case 4:
byte_en = 0xf;
data_tmp = val32 & 0xffffffff;
break;
default:
byte_en = 0xf;
data_tmp = val32 & 0xffffffff;
break;
}
}
else //read register
{
switch(len) {
case 1:
byte_en = 0x1;
break;
case 2:
byte_en = 0x3;
break;
case 4:
byte_en = 0xf;
break;
default:
byte_en = 0xf;
break;
}
if(domain_id == SPI_LOCAL_DOMAIN)
byte_en = 0;
}
cmd = FILL_SPI_CMD(byte_en, addr, domain_id, fun, ops_type);
//4 command segment bytes reorder
cmd = DWORD_endian_reverse(cmd, gspi_conf);
if ((ops_type == READ_REG)&& (domain_id!= SPI_RXFIFO_DOMAIN)) {
u32 read_data = 0;
_memset(spi_buf, 0x00, sizeof(spi_buf));
//SPI_OUT:32bit cmd
//SPI_IN:64bits status+ XXbits data
spi_buf[0] = cmd;
spi_buf[1] = 0;
spi_buf[2] = 0;
spi_buf[3] = 0;
spi_transfer((u8*)spi_buf, sizeof(spi_buf));
memcpy(status, (u8 *) &spi_buf[1], GSPI_STATUS_LEN);
read_data = spi_buf[3];
*(u32*)buf = DWORD_endian_reverse(read_data, gspi_conf);
}
else if (ops_type == WRITE_REG ) {
//4 data segment bytes reorder
data_tmp = DWORD_endian_reverse(data_tmp, gspi_conf);
//SPI_OUT:32bits cmd+ XXbits data
//SPI_IN:64bits status
spi_buf[0] = cmd;
spi_buf[1] = data_tmp;
spi_buf[2] = 0;
spi_buf[3] = 0;
spi_transfer((u8*)spi_buf, sizeof(spi_buf));
memcpy(status, (u8 *) &spi_buf[2], GSPI_STATUS_LEN);
}
// translate status
return ret;
}
u8 gspi_read8(u32 addr, s32 *err)
{
u32 ret = 0;
int val32 = 0 , remainder = 0 ;
s32 _err = 0;
_err = gspi_read_write_reg(READ_REG, addr&0xFFFFFFFC, (char *)&ret, 4, GSPI_CONFIG);
remainder = addr % 4;
val32 = ret;
val32 = (val32& (0xff<< (remainder<<3)))>>(remainder<<3);
if (err)
*err = _err;
return (u8)val32;
}
u16 gspi_read16(u32 addr, s32 *err)
{
u32 ret = 0;
int val32 = 0 , remainder = 0 ;
s32 _err = 0;
_err = gspi_read_write_reg(READ_REG, addr&0xFFFFFFFC,(char *)&ret, 4, GSPI_CONFIG);
remainder = addr % 4;
val32 = ret;
val32 = (val32& (0xffff<< (remainder<<3)))>>(remainder<<3);
if (err)
*err = _err;
return (u16)val32;
}
u32 gspi_read32(u32 addr, s32 *err)
{
unsigned int ret = 0;
s32 _err = 0;
_err = gspi_read_write_reg(READ_REG, addr&0xFFFFFFFC,(char *)&ret,4 ,GSPI_CONFIG);
if (err)
*err = _err;
return ret;
}
s32 gspi_write8(u32 addr, u8 buf, s32 *err)
{
int ret = 0;
ret = gspi_read_write_reg(WRITE_REG, addr, (char *)&buf,1, GSPI_CONFIG);
if (err)
*err = ret;
return ret;
}
s32 gspi_write16(u32 addr, u16 buf, s32 *err)
{
int ret = 0;
ret = gspi_read_write_reg(WRITE_REG,addr,(char *)&buf,2, GSPI_CONFIG);
if (err)
*err = ret;
return ret;
}
s32 gspi_write32(u32 addr, u32 buf, s32 *err)
{
int ret = 0;
ret = gspi_read_write_reg(WRITE_REG, addr,(char *)&buf,4, GSPI_CONFIG);
if (err)
*err = ret;
return ret;
}
int gspi_read_rx_fifo(u8 *buf, u32 len, struct spi_more_data * pmore_data,_gspi_conf_t gspi_conf)
{
int fun = 1;
u32 cmd = 0;
u8* spi_buf = (u8 *) (buf);
u8* spi_data = spi_buf + GSPI_CMD_LEN;
u8* spi_status = spi_data + len;
int spi_buf_len = GSPI_CMD_LEN + N_BYTE_ALIGMENT(len, 4) + GSPI_STATUS_LEN;
u8 dummy_bytes = 0;
cmd = FILL_SPI_CMD(len, ((len&0xff00) >>8), SPI_RXFIFO_DOMAIN, fun, (unsigned int)0);
//4 command segment bytes reorder
cmd = DWORD_endian_reverse(cmd, gspi_conf);
memcpy(spi_buf, (u8 *)&cmd, GSPI_CMD_LEN);
//4 clean data segment
memset(spi_data,0x00, len);
//4 clean status segment
memset(spi_status, 0x00, GSPI_STATUS_LEN);
spi_transfer((u8 *) spi_buf, spi_buf_len);
// data segement reorder
buf_endian_reverse(spi_data, len, &dummy_bytes, gspi_conf);
// status segment reorder
spi_status += dummy_bytes;
buf_endian_reverse(spi_status, GSPI_STATUS_LEN, &dummy_bytes, gspi_conf);
pmore_data->more_data = GET_STATUS_HISR(spi_status) & SPI_HIMR_RX_REQUEST_MSK;
pmore_data->len = GET_STATUS_RXQ_REQ_LEN(spi_status);
return 0;
}
static int gspi_write_tx_fifo(u8 *buf, u32 len, _gspi_conf_t gspi_conf)
{
int fun = 1; //TX_HIQ_FIFO
unsigned int cmd = 0;
u8 *spi_buf = (u8 *) (buf);
u8* spi_data = spi_buf + GSPI_CMD_LEN;
u8* spi_status;// = buf + len
u32 spi_buf_len = 0;
u32 NumOfFreeSpace;
u8 wait_num = 0;
u8 dummy_bytes = 0;
NumOfFreeSpace = gspi_read32(LOCAL_REG_FREE_TX_SPACE, NULL);
while (NumOfFreeSpace * (PACK_SIZE+SIZE_TX_DESC) < len) {
if((++wait_num) >= 4){
DBG_8195A("%s(): wait_num is >= 4\n", __FUNCTION__);
return -1;
}
rtw_udelay_os(100); //delay 100us
NumOfFreeSpace = gspi_read32(LOCAL_REG_FREE_TX_SPACE, NULL);
}
cmd = FILL_SPI_CMD(len, ((len&0xff00) >>8), SPI_TXFIFO_DOMAIN, fun, (unsigned int)1);
//4 command segment bytes reorder
cmd = DWORD_endian_reverse(cmd, gspi_conf);
memcpy(spi_buf, (u8 *)&cmd, GSPI_CMD_LEN);
//4 data segment bytes reorder
buf_endian_reverse(spi_data, len, &dummy_bytes, gspi_conf);
//4 status segment
spi_status = spi_data + len + dummy_bytes;
memset(spi_status, 0x00, GSPI_STATUS_LEN);
spi_buf_len = GSPI_CMD_LEN + len + dummy_bytes + GSPI_STATUS_LEN;
spi_transfer((u8 *) spi_buf, spi_buf_len);
// parse status infomation
// GET_STATUS_HISR(status)
// GET_STATUS_FREE_TX(status)
// GET_STATUS_RXQ_REQ_LEN(status)
// GET_STATUS_TX_SEQ(status)
return 0;
}
static int gspi_write_page(u8 *buf, u32 len, u8 agg_cnt){
int res;
u32 tot_len = SIZE_TX_DESC + len;
PGSPI_TX_DESC ptxdesc;
// clean GSPI command and tx descriptor area
memset(TX_BUFFER, 0, GSPI_CMD_LEN+SIZE_TX_DESC);
ptxdesc = (PGSPI_TX_DESC)(TX_BUFFER + GSPI_CMD_LEN); // reserve 4 byte for GSPI cmd
ptxdesc->txpktsize = len;
ptxdesc->offset = SIZE_TX_DESC;
ptxdesc->bus_agg_num = agg_cnt;
ptxdesc->type = GSPI_CMD_TX;
memcpy(TX_BUFFER+GSPI_CMD_LEN+SIZE_TX_DESC, buf, len);
res = gspi_write_tx_fifo(TX_BUFFER, tot_len, GSPI_CONFIG);
return res;
}
int gspi_configuration(_gspi_conf_t gspi_conf){
u8 conf = gspi_conf;
u8 retry_t = 0;
retry:
/*GSPI default mode: SPI_LITTLE_ENDIAN_32*/
gspi_read_write_reg(WRITE_REG, SPI_LOCAL_OFFSET|SPI_REG_SPI_CFG,(char *)&conf,1 ,SPI_LITTLE_ENDIAN_32);
// read gspi config
conf = 0xff;
conf = gspi_read8(SPI_LOCAL_OFFSET|SPI_REG_SPI_CFG, NULL);
if(conf != gspi_conf){
if(++ retry_t <= 3)
goto retry;
DBG_8195A("%s: config fail@ 0x%x\n", __FUNCTION__, conf);
return 1;
}
char *s;
switch (conf) {
case SPI_LITTLE_ENDIAN_16:
s = "LITTLE_ENDIAN|WORD_LEN_16"; break;
case SPI_LITTLE_ENDIAN_32:
s = "LITTLE_ENDIAN|WORD_LEN_32"; break;
case SPI_BIG_ENDIAN_16:
s = "BIG_ENDIAN|WORD_LEN_16"; break;
case SPI_BIG_ENDIAN_32:
s = "BIG_ENDIAN|WORD_LEN_32"; break;
default:
s = "UNKNOW CONFIGURATION"; break;
};
DBG_8195A("%s: Current configuration:%s\n", __FUNCTION__, s);
return 0;
}
u8 check_trx_data(u8 *src,u8*dst,u16 len){
u16 i;
u8 result=1;
for(i=0;i<len;i++)
if(*(src+i) !=*(dst+i)){
result=0;
break;
}
return result;
}
#if CONFIG_USE_INTERRUPT
void spi_interrupt_thread(){
u32 spi_hisr;
u32 spi_himr;
u32 rx_cnt = 0;
while(1){
if (rtw_down_sema(&pspiIrqSemaphore) == _FAIL){
DBG_8195A("%s, Take Semaphore Fail\n", __FUNCTION__);
goto exit;
}
spi_himr = gspi_read32(SPI_LOCAL_OFFSET | SPI_REG_HIMR, NULL);
spi_hisr = gspi_read32(SPI_LOCAL_OFFSET | SPI_REG_HISR, NULL);
if (spi_hisr & spi_himr){
if(spi_hisr & SPI_HISR_RX_REQUEST) {
u8* rx_buf = NULL;
u8* payload = NULL;
u32 rx_len = 0;
u8 rx_len_rdy = 0;
PINIC_RX_DESC prxdesc;
struct spi_more_data more_data = {0};
// clean RX buffer
memset(RX_DATA, 0, AGG_SIZE + 100);
rx_buf = RX_DATA;
do {
//validate RX_LEN_RDY before reading RX0_REQ_LEN
if(rx_len==0){
rx_len_rdy = gspi_read8(SPI_LOCAL_OFFSET|(SPI_REG_RX0_REQ_LEN + 3), NULL);
if(rx_len_rdy & BIT7){
rx_len = (gspi_read32(SPI_LOCAL_OFFSET | SPI_REG_RX0_REQ_LEN, NULL)) &0xffffff;
}
}
if (rx_len >(PACK_SIZE+SIZE_RX_DESC))
rx_len = PACK_SIZE+SIZE_RX_DESC;
if(rx_len){
memset(RX_BUFFER, 0, BUFFER_LEN);
gspi_read_rx_fifo(RX_BUFFER, rx_len, &more_data,GSPI_CONFIG);
memcpy(rx_buf, RX_BUFFER+GSPI_CMD_LEN, rx_len);
prxdesc = (PINIC_RX_DESC)rx_buf;
DBG_8195A("Receive Data lenth = %d (cnt = %d)\n",prxdesc->pkt_len, ++rx_cnt);
payload = rx_buf + prxdesc->offset;
rx_buf += rx_len;
rx_len = 0;
rx_done=1;
}else{
break;
}
}while(1);
}
}
// query other interrupt here
}
exit:
vTaskDelete(NULL);
}
#endif
// external GSPI interrupt handler
void gspi_irq_handler (uint32_t id, gpio_irq_event event)
{
//DBG_8195A("gspi_irq_handler....\n");
if(!pspiIrqSemaphore)
return;
rtw_up_sema_from_isr(&pspiIrqSemaphore);
}
// SPI master interrupt callback if use interrupt mode
void spi_tx_rx_intr_callback(void *pdata, SpiIrq event){
switch(event){
case SpiRxIrq:
rxDone = TRUE;
break;
case SpiTxIrq:
txDone = TRUE;
break;
default:
DBG_8195A("unknown interrput evnent!\n");
}
}
void spi_tx_bus_idle_callback(void *pdata, SpiIrq event){
txbusIdle = TRUE;
}
void spi_init_intr(){
#if CONFIG_USE_INTERRUPT
// init gspi external interrupt
gpio_irq_init(&gpio_int, GPIO_INT, gspi_irq_handler, NULL);
gpio_irq_set(&gpio_int, IRQ_FALL, 1); // Falling Edge Trigger
gpio_irq_enable(&gpio_int);
#endif
// init spi master tx/rx done interrupt
spi_irq_hook(&spi0_master, (spi_irq_handler)spi_tx_rx_intr_callback, NULL);
// init spi master tx bus idle interrupt
spi_bus_tx_done_irq_hook(&spi0_master, (spi_irq_handler)spi_tx_bus_idle_callback, NULL);
}
void spi_init_master(){
// init spi master
spi0_master.spi_idx=MBED_SPI1;
spi_init(&spi0_master, SPI0_MOSI, SPI0_MISO, SPI0_SCLK, SPI0_CS);
spi_format(&spi0_master, SPI_BITS, 0, 0);
spi_frequency(&spi0_master, SPI0_FREQUENCY);
printf("spi master frequency %d Hz\n",SPI0_FREQUENCY);
gpio_init(&gpio_cs, GPIO_CS);
gpio_mode(&gpio_cs, PullDown);
gpio_dir(&gpio_cs, PIN_OUTPUT);
SLAVE_DESELECT(); // deselect slave
}
#endif
void gspi_demo(void)
{
#if CONFIG_GSPI_SLAVE
int i;
DBG_8195A("Init GSPI slave....\n");
spdio_dev.priv = NULL;
spdio_dev.rx_bd_num = SPDIO_RX_BD_NUM;
spdio_dev.tx_bd_num = SPDIO_TX_BD_NUM;
spdio_dev.rx_bd_bufsz = SPDIO_RX_BUFSZ;
spdio_dev.rx_buf = (struct spdio_buf_t *)rtw_malloc(SPDIO_RX_BD_NUM*sizeof(struct spdio_buf_t));
for(i=0;i<SPDIO_RX_BD_NUM;i++){
spdio_dev.rx_buf[i].buf_allocated = (u32)rtw_malloc(SPDIO_RX_BUFSZ + SPDIO_DMA_ALIGN_4);
if(!spdio_dev.rx_buf[i].buf_allocated){
printf("malloc failed for spdio buffer!\n");
return;
}
spdio_dev.rx_buf[i].size_allocated = SPDIO_RX_BUFSZ + SPDIO_DMA_ALIGN_4;
// this buffer must be 4 byte alignment
spdio_dev.rx_buf[i].buf_addr = (u32)N_BYTE_ALIGMENT((u32)(spdio_dev.rx_buf[i].buf_allocated), SPDIO_DMA_ALIGN_4);
}
spdio_dev.rx_done_cb = ex_gspi_rx_done_cb;
spdio_dev.tx_done_cb = ex_gspi_tx_done_cb;
DBG_INFO_MSG_OFF(_DBG_SDIO_);
DBG_WARN_MSG_OFF(_DBG_SDIO_);
DBG_ERR_MSG_ON(_DBG_SDIO_);
spdio_init(&spdio_dev);
DBG_8195A("Init GSPI slave Done,Ready for TRx....\n");
#else
DBG_8195A("Init SPI master....\n");
u32 spi_himr = 0;
u32 spi_hisr = 0;
u32 spi_ictlr = 0;
u32 rx_agg_ctrl = 0;
s8 res = 0;
int test_loop = 1000;
u16 counter=0;
//1 SPI host init
spi_init_master();
spi_init_intr();
rtw_init_sema(&pspiIrqSemaphore, 0);
// used for sync SPI bus, SPI bus shold not be interrupt
rtw_mutex_init(&SPIbusbusy);
if( xTaskCreate( (TaskFunction_t)spi_interrupt_thread, "SPI INTERRUPT", (TASK_STACK_SIZE/4), NULL, TASK_PRIORITY+2, NULL) != pdPASS) {
DBG_8195A("Cannot create SPI INTERRUPT task\n\r");
goto err;
}
//1 GSPI slave configuration
res = gspi_configuration(GSPI_CONFIG);
if(res){
DBG_8195A("gspi configure error....\n");
while(1);
}
// INT_CTRL-clean INT control register
spi_ictlr = 0;
gspi_write32(SPI_LOCAL_OFFSET |SPI_REG_INT_CTRL, spi_ictlr, NULL);
// HISR - clean interrupt status register
gspi_write32(SPI_LOCAL_OFFSET |SPI_REG_HISR, 0xFFFFFFFF, NULL);
// HIMR - turn all off
gspi_write32(SPI_LOCAL_OFFSET |SPI_REG_HIMR, SPI_HIMR_DISABLED, NULL);
// Set intterrupt mask
spi_himr = (u32)(SPI_HISR_RX_REQUEST|SPI_HISR_CPWM1_INT);
// Write and enable interrupt
gspi_write32(SPI_LOCAL_OFFSET | SPI_REG_HIMR, spi_himr, NULL);
#if 1
// set RX AGG control register
rx_agg_ctrl = 0;
gspi_write32(SPI_LOCAL_OFFSET | SPI_REG_RX_AGG_CTL, rx_agg_ctrl, NULL);
#endif
DBG_8195A("Loopback Test Start...\n");
// prepare test data (0x00-0xFF, 0x00-0xFF......)
for(int i=0;i<PACK_SIZE;i++)
memset(TX_DATA+i, i%256, 1);
do{
res = gspi_write_page(TX_DATA, PACK_SIZE, 1);
if(res) {
DBG_8195A("spi_write_page: Error!\n");
// handle error msg here
}
counter=0;
while (!rx_done){
counter++;
rtw_mdelay_os(10);
if(counter==100){
DBG_8195A("Master Rx data Timeout... test aborted!\n");
goto err;
}
}
rx_done=0;
if(check_trx_data(TX_DATA,RX_DATA+SIZE_RX_DESC,PACK_SIZE))
DBG_8195A("loop %d Test Succeed!\n",1000-test_loop);
else {
DBG_8195A("loop %d Test Failed!\n",1000-test_loop);
goto err;
}
rtw_mdelay_os(500);
}while(--test_loop);
#if !CONFIG_USE_INTERRUPT
#endif
#endif
err:
// spi_free(&spi0_master);
/* Kill init thread after all init tasks done */
vTaskDelete(NULL);
}
void main(void)
{
// create demo Task
if( xTaskCreate( (TaskFunction_t)gspi_demo, "GSPI DEMO", (TASK_STACK_SIZE/4), NULL, TASK_PRIORITY, NULL) != pdPASS) {
DBG_8195A("Cannot create demo task\n\r");
}
#if defined(CONFIG_KERNEL) && !TASK_SCHEDULER_DISABLED
#ifdef PLATFORM_FREERTOS
vTaskStartScheduler();
#endif
#else
#error !!!Need FREERTOS!!!
#endif
}

View file

@ -0,0 +1,273 @@
/**
******************************************************************************
* @file rtl8710b_gspi_host.h
* @author
* @version V1.0.0
* @date 2016-12-9
* @brief This file contains all the functions prototypes for the GSPI firmware
* library.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2015, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#ifndef __RTL8710B_GSPI_H__
#define __RTL8710B_GSPI_H__
#define SPI_LOCAL_DOMAIN 0x0
#define SPI_TXFIFO_DOMAIN 0xc
#define SPI_RXFIFO_DOMAIN 0x1f
//IO Bus domain address mapping
#define DEFUALT_OFFSET 0x0
#define SPI_LOCAL_OFFSET 0x10250000
#define SPI_TX_FIFO_OFFSET 0x10310000
#define SPI_RX_FIFO_OFFSET 0x10340000
#define SPI_LOCAL_DEVICE_ID 0
#define SPI_TXQ_FIFO_DEVICE_ID 3
#define SPI_RXQ_FIFO_DEVICE_ID 7
#define SPI_UNDEFINED_DEVICE_ID (-1)
//SPI Local registers
#define SPI_REG_INT_CTRL 0x0004 // 4 bytes, SPI INT Control
#define SPI_REG_INT_TIMEOUT 0x0006 // 2 bytes, SPI 32us INT timout
#define SPI_REG_HIMR 0x0014 // 4 bytes, SPI Host Interrupt Mask
#define SPI_REG_HISR 0x0018 // 4 bytes, SPI Host Interrupt Service Routine
#define SPI_REG_RX0_REQ_LEN 0x001C // 4 bytes, RXDMA Request Length
#define SPI_REG_FREE_TX_SPACE 0x0020 // 4 bytes, Free Tx Buffer Page
#define SPI_REG_TX_SEQNUM 0x0024 // 1 byte, TX Sequence Number Definition
#define SPI_REG_HCPWM 0x0038 // 1 byte, HCI Current Power Mode
#define SPI_REG_HCPWM2 0x003A // 2 bytes, HCI Current Power Mode 2
#define SPI_REG_AVAI_PATH_L 0x0040 // 4 bytes, SPI TX Available Low Size reg
#define SPI_REG_AVAI_PATH_H 0x0044 // 4 bytes, SPI TX Available High Size reg
#define SPI_REG_RX_AGG_CTL 0x0048 // 4 bytes, SPI RX AGG control
#define SPI_REG_H2C_MSG 0x004C // 4 bytes, SPI_REG_H2C_MSG
#define SPI_REG_C2H_MSG 0x0050 // 4 bytes, SPI_REG_C2H_MSG
#define SPI_REG_HRPWM 0x0080 // 1 byte, SPI_REG_HRPWM
#define SPI_REG_HRPWM2 0x82 // 2bytes, driver to FW, host domain, sync to CRPWM2
#define SPI_REG_HPS_CLKR 0x0084 // 1 byte, not uesd
#define SPI_REG_CPU_IND 0x0087 // 1 byte, firmware indication to host
#define SPI_REG_32K_TRANS_CTL 0x0088 // 1 byte, 32K transparent control, BIT0 EN32K_TRANS
#define SPI_REG_32K_IDLE_TIME 0x008B // 1 byte, 32K idle time,
#define SPI_REG_DELY_LINE_SEL 0x008C // 1 byte, Delay line selection,
#define SPI_REG_SPI_CFG 0x00F0 // 1 byte, SPI configuration,
#define LOCAL_REG_FREE_TX_SPACE (SPI_LOCAL_OFFSET | SPI_REG_FREE_TX_SPACE)
// Register SPI_REG_CPU_IND
#define SPI_CPU_RDY_IND (BIT0)
#define SPI_MEM_WR_DONE (BIT1)
/************************************************/
// SPI_REG_HISR: SDIO Host Interrupt Service Routine
#define SPI_HISR_RX_REQUEST (BIT0)
#define SPI_HISR_AVAL_INT (BIT1)
#define SPI_HISR_TXPKT_OVER_BUFF (BIT2)
#define SPI_HISR_TX_AGG_SIZE_MISMATCH (BIT3)
#define SPI_HISR_TXBD_OVF (BIT4)
//BIT5~16 not used
#define SPI_HISR_C2H_MSG_INT (BIT17)
#define SPI_HISR_CPWM1_INT (BIT18)
#define SPI_HISR_CPWM2_INT (BIT19)
//BIT20~31 not used
#define SPI_HISR_CPU_NOT_RDY (BIT22)
/*
#define MASK_SPI_HISR_CLEAR (SPI_HISR_RX_REQUEST |\
SPI_HISR_AVAL_INT |\
SPI_HISR_TXPKT_OVER_BUFF |\
SPI_HISR_TX_AGG_SIZE_MISMATCH |\
SPI_HISR_TXBD_OVF |\
SPI_HISR_C2H_MSG_INT |\
SPI_HISR_CPWM1_INT |\
SPI_HISR_CPWM2_INT)
*/
#define MASK_SPI_HISR_CLEAR (SPI_HISR_TXPKT_OVER_BUFF |\
SPI_HISR_TX_AGG_SIZE_MISMATCH |\
SPI_HISR_TXBD_OVF |\
SPI_HISR_C2H_MSG_INT |\
SPI_HISR_CPWM1_INT |\
SPI_HISR_CPWM2_INT)
// RTL8195A SPI Host Interrupt Mask Register
#define SPI_HIMR_RX_REQUEST_MSK (BIT0)
#define SPI_HIMR_AVAL_MSK (BIT1)
#define SPI_HIMR_TXPKT_SIZE_OVER_BUFF_MSK (BIT2)
#define SPI_HIMR_AGG_SIZE_MISMATCH_MSK (BIT3)
#define SPI_HIMR_TXBD_OVF_MSK (BIT4)
//BIT5~16 not used
#define SPI_HIMR_C2H_MSG_INT_MSK (BIT17)
#define SPI_HIMR_CPWM1_INT_MSK (BIT18)
#define SPI_HIMR_CPWM2_INT_MSK (BIT19)
//BIT20~31 not used
#define SPI_HIMR_DISABLED 0
// Register SPI_REG_HCPWM
#define SPI_HCPWM_WLAN_TRX (BIT1)
enum{
SPI_LITTLE_ENDIAN = 2,
SPI_BIG_ENDIAN = 0
};
enum{
SPI_WORD_LEN_16 = 0,
SPI_WORD_LEN_32 = 1
};
typedef enum{
SPI_LITTLE_ENDIAN_16 = SPI_LITTLE_ENDIAN|SPI_WORD_LEN_16,
SPI_LITTLE_ENDIAN_32 = SPI_LITTLE_ENDIAN|SPI_WORD_LEN_32, // default configure
SPI_BIG_ENDIAN_16 = SPI_BIG_ENDIAN|SPI_WORD_LEN_16,
SPI_BIG_ENDIAN_32 = SPI_BIG_ENDIAN|SPI_WORD_LEN_32
}_gspi_conf_t;
#define GSPI_CMD_LEN 4
#define GSPI_STATUS_LEN 8
#define FILL_SPI_CMD(byte_en, addr, domain_id, fun, write_flag) ((byte_en & 0xff) | ((addr & 0xffff) << 8) \
| ((domain_id & 0x1f) << 24) | ((fun & 0x3) << 29) | ((write_flag & 0x1) << 31))
#define GET_STATUS_HISR(status) ((((*(u32*)status)) & 0x3) |((((*(u32*)status) >> 2) & 0x7) << 17))
#define GET_STATUS_FREE_TX(status) ((((*(u32*)status) >> 5) & 0x7ffffff) << 2)
#define GET_STATUS_RXQ_REQ_LEN(status) (((*(u32*)((u8 *)status + 4))) & 0xffffff)
#define GET_STATUS_TX_SEQ(status) (((*(u32*)((u8 *)status + 4)) >> 24) & 0xff)
#define GSPI_CMD_TX 0x83 //
#define GSPI_CMD_RX 0X82
// define transmit packat type
#define GPSI_TX_PACKET_802_3 (0x83)
#define GSPI_TX_PACKET_802_11 (0x81)
#define GSPI_TX_H2C_CMD (0x11)
#define GSPI_TX_MEM_READ (0x51)
#define GSPI_TX_MEM_WRITE (0x53)
#define GSPI_TX_MEM_SET (0x55)
#define GSPI_TX_FM_FREETOGO (0x61)
#define GSPI_TX_PACKET_USER (0x41)
//define receive packet type
#define GSPI_RX_PACKET_802_3 (0x82)
#define GSPI_RX_PACKET_802_11 (0x80)
#define GSPI_RX_C2H_CMD (0x10)
#define GSPI_RX_MEM_READ (0x50)
#define GSPI_RX_MEM_WRITE (0x52)
#define GSPI_RX_MEM_SET (0x54)
#define GSPI_RX_FM_FREETOGO (0x60)
#define GSPI_RX_PACKET_USER (0x40)
typedef struct {
// u4Byte 0
#if (SYSTEM_ENDIAN==PLATFORM_LITTLE_ENDIAN)
u32 txpktsize:16; // bit[15:0]
u32 offset:8; // bit[23:16], store the sizeof(TX_DESC)
u32 bus_agg_num:8; // bit[31:24], the bus aggregation number
#else
u32 bus_agg_num:8; // bit[31:24], the bus aggregation number
u32 offset:8; // bit[23:16], store the sizeof(TX_DESC)
u32 txpktsize:16; // bit[15:0]
#endif
// u4Byte 1
#if (SYSTEM_ENDIAN==PLATFORM_LITTLE_ENDIAN)
u32 type:8; // bit[7:0], the packet type
u32 data:8; // bit[8:15], the value to be written to the memory
u32 reply:1; // bit[16], request to send a reply message
u32 rsvd0:15;
#else
u32 rsvd0:15;
u32 reply:1; // bit[16], request to send a reply message
u32 data:8; // bit[8:15], the value to be written to the memory
u32 type:8; // bit[7:0], the packet type
#endif
// u4Byte 2
u32 start_addr; // memory write/read start address, function start address
// u4Byte 3
#if (SYSTEM_ENDIAN==PLATFORM_LITTLE_ENDIAN)
u32 data_len:16; // bit[15:0], the length to write/read
u32 rsvd2:16; // bit[31:16]
#else
u32 rsvd2:16; // bit[31:16]
u32 data_len:16; // bit[15:0], the length to write/read
#endif
} GSPI_TX_DESC, *PGSPI_TX_DESC;
typedef struct {
// u4Byte 0
#if (SYSTEM_ENDIAN==PLATFORM_LITTLE_ENDIAN)
u32 pkt_len:16; // bit[15:0], the packet size
u32 offset:8; // bit[23:16], the offset from the packet start to the buf start, also means the size of RX Desc
u32 rsvd0:6; // bit[29:24]
u32 icv:1; //icv error
u32 crc:1; // crc error
#else
u32 rsvd0:6; // bit[29:24]
u32 icv:1; //icv error
u32 crc:1; // crc error
u32 offset:8; // bit[23:16], the offset from the packet start to the buf start, also means the size of RX Desc
u32 pkt_len:16; // bit[15:0], the packet size
#endif
// u4Byte 1
/************************************************/
/*****************receive packet type*********************/
/* 0x82: 802.3 packet */
/* 0x80: 802.11 packet */
/* 0x10: C2H command */
/* 0x50: Memory Read */
/* 0x52: Memory Write */
/* 0x54: Memory Set */
/* 0x60: Indicate the firmware is started */
#if (SYSTEM_ENDIAN==PLATFORM_LITTLE_ENDIAN)
u32 type:8; // bit[7:0], the type of this packet
u32 rsvd1:24; // bit[31:8]
#else
u32 rsvd1:24; // bit[31:8]
u32 type:8; // bit[7:0], the type of this packet
#endif
// u4Byte 2
u32 start_addr;
// u4Byte 3
#if (SYSTEM_ENDIAN==PLATFORM_LITTLE_ENDIAN)
u32 data_len:16; // bit[15:0], the type of this packet
u32 result:8; // bit[23:16], the result of memory write command
u32 rsvd2:8; // bit[31:24]
#else
u32 rsvd2:8; // bit[31:24]
u32 result:8; // bit[23:16], the result of memory write command
u32 data_len:16; // bit[15:0], the type of this packet
#endif
} GSPI_RX_DESC, *PGSPI_RX_DESC;
#define SIZE_TX_DESC (sizeof(GSPI_TX_DESC))
#define SIZE_RX_DESC (sizeof(GSPI_RX_DESC))
// CCPWM2 bit map definition for Firmware download
#define GSPI_INIT_DONE (BIT0)
#define GSPI_MEM_WR_DONE (BIT1)
#define GSPI_MEM_RD_DONE (BIT2)
#define GSPI_MEM_ST_DONE (BIT3)
#define GSPI_CPWM2_TOGGLE (BIT15)
// Register REG_SPDIO_CPU_IND
#define GPSI_SYSTEM_TRX_RDY_IND (BIT0)
#endif //__GSPI_REG_H__