Files
banban/ql-kernel/threadx/lcd/src/spi_drv.c
T

914 lines
30 KiB
C

#include "spi_drv.h"
#include "quec_rtos.h"
#include "qspi_dma.h"
#include "lcd_log.h"
#include "cgpio.h"
#include "panel_drv.h"
#define TX_FIFO_INT_EN (0x1<<3) //SSP_INT_EN[3]
#define RX_FIFO_INT_EN (0x1<<2) //SSP_INT_EN[2]
#define TIMEOUT_EN (0x1<<1) //SSP_INT_EN[1]
#define PERI_TRAIL_EN (0x1<<0) //SSP_INT_EN[0]
#define SSPSFRM_M (0x0<<4) //SSP_TOP_CTRL[4]
#define SSPSCLK_M (0x0<<3) //SSP_TOP_CTRL[3]
#define FRF_SPI (0x0<<1) //SSP_TOP_CTRL[2:1]
#define SSP_FORMAT FRF_SPI
#define RX_AUTO_FULL_CTRL_EN (0x1<<17) //SSP_FIFO_CTRL[17]
#define FIFO_UNPACKING (0x0<<16) //SSP_FIFO_CTRL[16]
#define RX_THRES_7 (0x7<<5) //SSP_FIFO_CTRL[9:5]
#define TX_THRES_7 (0x7<<0) //SSP_FIFO_CTRL[4:0]
#define SSE_EN (0x1<<0) //SSP_TOP_CTRL[0]
#define SSP0_BASE_ADDRESS 0xD401B000
#define APB_SSP0_CLK_RST 0xd401501c
#define SSP2_BASE_ADDRESS 0xD401C000
#define APB_SSP2_CLK_RST 0xd401504c
#define LCD_BASE_ADDR SSP0_BASE_ADDRESS
#define DW_9BITS (0x8 << 5)
#define SSP_DATAR 0x10
#define SSP__STATUS 0x14
#define DMA_BASE_ADDRESS 0xD4000000
#define REG32(x) *((volatile unsigned long*)(x))
#define SSP_TX_DMA_DESC 0x20 /*dma描述符个数,个数越多传输数据量越大*/
__align(32) UINT8 SPI_TX_DESCRIPTO[SSP_TX_DMA_DESC*sizeof(DMA_DESCRIPTOR)]={0};
static OS_HISR spi_dma_hisr_ref;
volatile P_QSPI_XLLP_DMAC_T DMA_ADDR=(P_QSPI_XLLP_DMAC_T)(volatile unsigned int*)0xd4000000;
volatile unsigned int dma_tx_complete = 0;
unsigned int send_flag_error = 0;
struct s_spi_ctx g_spi_ctx;
quec_flag_t g_lcd_interrupt_flag;
extern void dma_load_descriptor(P_DMA_DESCRIPTOR p_desc, uint32_t channel);
extern void CacheCleanMemory( void *pMem ,UINT32 size);
#define REGS_MFPR_BASE 0xD401E000
#define REG32(x) *((volatile unsigned long*)(x))
#define write32(addr, val) (*(volatile unsigned int *)(addr) = (val))
void mfp_config(const unsigned int * mfp_cfgs)
{
volatile uint32 p_mfpr = 0;
volatile uint32 mfpr_offset = 0;
volatile uint32 cfg_val, val;
while (1) {
cfg_val = *mfp_cfgs++;
/* exit if End of configuration table detected */
if (cfg_val == MFP_EOC)
break;
//mfpr_offset = MFP_REG_GET_OFFSET(cfg_val);
mfpr_offset = cfg_val >> 16;
p_mfpr = (uint32) (REGS_MFPR_BASE + mfpr_offset);
/* Write a mfg register as per configuration */
val = 0;
if (cfg_val & MFP_VALUE_MASK)
val = cfg_val & MFP_VALUE_MASK;
// raw_uart_log("before mfpr register %#x %#x set:%#x\n", p_mfpr, REG32(p_mfpr), val);
if(REG32(p_mfpr)!=val)
write32(p_mfpr, val);
// raw_uart_log("mfpr register %#x = %#x\n",p_mfpr,REG32(p_mfpr));
}
return;
}
struct s_spi_ctx* spi_get_interface(void)
{
return &g_spi_ctx;
}
//atomic operation to fill single descriptor.
static void _dma_config_desc(P_DMA_DESCRIPTOR p_des,
P_DMA_DESCRIPTOR p_next_des,
unsigned int stop,
unsigned int branch_mode,
unsigned int src,
unsigned int trg,
P_DMA_CMDx_T pCMD)
{
unsigned int next_des_addr = (unsigned int)p_next_des;
if(!stop){
//clear the reserved bits.
next_des_addr = next_des_addr & DMA_DDADR_RESERVED_MASK;
}else{
next_des_addr = 0;
}
next_des_addr |= ( (stop & 0x1) | ( (branch_mode&0x1) << 1) );
//fill the descriptor entries.
p_des->DDADR = (unsigned int)next_des_addr;
p_des->DSADR = (unsigned int)src;
p_des->DTADR = (unsigned int)trg;
p_des->DCMD = (unsigned int)pCMD->value;
return;
}
/**
* Configure the descriptor entries.
* p_des should be malloc ahead and the malloc size can be got by dma_get_des_num().
* Descriptor, source and target address should align.
*/
void spi_dma_config_desc(P_DMA_DESCRIPTOR p_des,P_DMA_CMDx_T pCMD,unsigned int src, unsigned int trg,unsigned int bytes_len)
{
unsigned int bytes_step = (unsigned int)pCMD->bits.Length;
unsigned int des_num = bytes_len / bytes_step;
unsigned int bytes_tail = bytes_len % bytes_step;
unsigned int i = 0;
unsigned int p_cur_des;
unsigned int p_next_des = 0;
if(bytes_tail != 0){
des_num++;
}else{
bytes_tail = bytes_step;
}
p_cur_des= (unsigned int)p_des;
for(i=0; i<des_num-1; i++){
p_cur_des = (unsigned int)p_des + i*sizeof(DMA_DESCRIPTOR);
p_next_des = (unsigned int)p_des + (i+1)*sizeof(DMA_DESCRIPTOR);
_dma_config_desc((P_DMA_DESCRIPTOR)p_cur_des, (P_DMA_DESCRIPTOR)p_next_des, 0, 0, src, trg, pCMD);
// For some cases, such as ssp fifo. FIFO address should set src_inc but the address may not increase.
if(pCMD->bits.IncSrcAddr)
src = src + pCMD->bits.Length;
if(pCMD->bits.IncTrgAddr)
trg = trg + pCMD->bits.Length;
}
//handle the tail bytes.
p_cur_des = (unsigned int)p_des + (des_num-1)*sizeof(DMA_DESCRIPTOR);
p_next_des = (unsigned int)p_des + des_num*sizeof(DMA_DESCRIPTOR);
pCMD->bits.Length = bytes_tail;
_dma_config_desc((P_DMA_DESCRIPTOR)p_cur_des, (P_DMA_DESCRIPTOR)p_next_des, 1, 0, src, trg, pCMD);
if(des_num>1)
pCMD->bits.Length = bytes_step;//reset the pCMD.
return;
}
void spi_dma_tx_hisr(void)
{
int ret;
ret = quec_rtos_flag_release(g_lcd_interrupt_flag, SPI_INTER_FLAG_FRAMEDONE, QUEC_FLAG_OR);
if (ret != 0) {
send_flag_error++;
}
}
void ClearDmaInterrupt( unsigned int channel )
{
DMA_ADDR->DCSR[channel] &= ~CSR_STOPIRQEN;
}
int spi_dma_tx_complete_handler(unsigned int val)
{
struct s_spi_ctx* spi_ctx=spi_get_interface();
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
if(DMA_ADDR->DCSR[DMA_DEV_LCD_TX_CH] & CSR_STOPINTR)
{
OS_Activate_HISR(&spi_dma_hisr_ref);
ClearDmaInterrupt(DMA_DEV_LCD_TX_CH);
}
break;
case SPI_CONETROLER_0:
if(DMA_ADDR->DCSR[DMA_DEV_LCD_TX_CH] & CSR_STOPINTR)
{
OS_Activate_HISR(&spi_dma_hisr_ref);
ClearDmaInterrupt(DMA_DEV_LCD_TX_CH);
}
break;
default:
LCDLOGE("!!!");
break;
}
return 0;
}
void spi_dma_init(void)
{
struct s_spi_ctx* spi_ctx=spi_get_interface();
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
OS_Create_HISR(&spi_dma_hisr_ref, "tx_ssp2_dma_hisr", spi_dma_tx_hisr, HISR_PRIORITY_2);
dma_irq_callback_register(spi_dma_tx_complete_handler, DMA_DEV_LCD_TX_CH);
dma_map_device_to_channel(DMA_REQ_SSP2_TX, DMA_DEV_LCD_TX_CH);
set_user_aligment(DMA_DEV_LCD_TX_CH); // 1 = user aligned (source and target addresses)
break;
case SPI_CONETROLER_0:
OS_Create_HISR(&spi_dma_hisr_ref, "tx_ssp0_dma_hisr", spi_dma_tx_hisr, HISR_PRIORITY_2);
dma_irq_callback_register(spi_dma_tx_complete_handler, DMA_DEV_LCD_TX_CH);
dma_map_device_to_channel(DMA_REQ_SSP0_TX, DMA_DEV_LCD_TX_CH);
set_user_aligment(DMA_DEV_LCD_TX_CH); // 1 = user aligned (source and target addresses)
break;
default:
LCDLOGE("dma init failed");
break;
}
quec_rtos_flag_create(&g_lcd_interrupt_flag);
}
/*************************************************************************
RFT: RXFIFO Trigger Threshold (bit 13:10)
TFT: TXFIFO Trigger Threshold (bit 9:6)
TFT = RFT -1
DMA burst size <= DMA Width * RFT (in unpack mode of SSP FIFO)
=========================================================
DMA Width | DMA burst size | RFT | TFT
-----------+------------------+------+-------
2 Bytes | 16 Bytes | 8 | 7
-----------+------------------+------+-------
4 Bytes | 16 Bytes | 4 | 3
-----------+------------------+------+-------
4 Byets | 32 Byets | 8 | 7
=========================================================
*************************************************************************/
void spi_dma_transfer_request(spidir dir, uint16 *buf, unsigned int size)
{
DMA_CMDx_T cmd;
DMA_DESCRIPTOR* TX_Desc = NULL;
struct s_spi_ctx* spi_ctx=spi_get_interface();
if(dir == spi_rx){//rx对于lcd这部分没用
cmd.value = 0;
cmd.bits.IncSrcAddr = 0; //Always use SSP_DR
cmd.bits.IncTrgAddr = 1; //Increase in SPI_RXBuffer[]
cmd.bits.FlowTrg = 0; //Target(SPI_RXBuffer) is memory, not need flow control
cmd.bits.FlowSrc = 1; //Source(SSP_DR) is on-chip peripheral, need flow control
cmd.bits.Width = 2;
cmd.bits.MaxBurstSize = 2;
cmd.bits.Length = size * sizeof(short);
dma_set_reg_nf((unsigned int)(SSP0_BASE_ADDRESS + SSP_DATAR), (unsigned int)buf, &cmd,DMA_DEV_SSP0_RX_CH);
dma_xfer_start(DMA_DEV_SSP0_RX_CH);
dma_stop_irq_en(DMA_DEV_SSP0_RX_CH);
}
else{
cmd.value = 0;
cmd.bits.IncSrcAddr = 1;//Increase in SPI_TXBuffer[] memory
cmd.bits.IncTrgAddr = 0; //Always use SSP_DR
cmd.bits.FlowTrg = 1; //Target(SSP_DR) is on-chip peripheral, need flow control
cmd.bits.FlowSrc = 0; //Source(SPI_TXBuffer) is memory, not need flow control
cmd.bits.Width = 2; //Width of onchip peripheral - 0=reserved, 1=1B, 2=2B, 3=4B
cmd.bits.MaxBurstSize = 2; //Max Burst Size - 0=reserved, 1=8B, 2=16B, 3=32B
cmd.bits.Length = (size > 8191) ? (7936):size;
cmd.bits.EndIRQEn = 1; //Enable End Interrupt
TX_Desc = (DMA_DESCRIPTOR*)(SPI_TX_DESCRIPTO);
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
spi_dma_config_desc(TX_Desc, &cmd, (unsigned int)buf, (unsigned int)(SSP2_BASE_ADDRESS + SSP_DATAR), size);
dma_set_reg_nf((unsigned int)buf, (unsigned int)(SSP2_BASE_ADDRESS + SSP_DATAR), &cmd,DMA_DEV_LCD_TX_CH);
dma_load_descriptor(&TX_Desc[0], DMA_DEV_LCD_TX_CH);
CacheCleanMemory((void *) TX_Desc, SSP_TX_DMA_DESC * sizeof(DMA_DESCRIPTOR));
dma_stop_irq_en(DMA_DEV_LCD_TX_CH);
dma_xfer_start(DMA_DEV_LCD_TX_CH);
break;
case SPI_CONETROLER_0:
spi_dma_config_desc(TX_Desc, &cmd, (unsigned int)buf, (unsigned int)(SSP0_BASE_ADDRESS + SSP_DATAR), size);
dma_set_reg_nf((unsigned int)buf, (unsigned int)(SSP0_BASE_ADDRESS + SSP_DATAR), &cmd,DMA_DEV_LCD_TX_CH);
dma_load_descriptor(&TX_Desc[0], DMA_DEV_LCD_TX_CH);
CacheCleanMemory((void *) TX_Desc, SSP_TX_DMA_DESC * sizeof(DMA_DESCRIPTOR));
dma_stop_irq_en(DMA_DEV_LCD_TX_CH);
dma_xfer_start(DMA_DEV_LCD_TX_CH);
break;
default:
LCDLOGE("dma enable failed");
break;
}
//raw_uart_log("--------config dma----------\r\n");
}
return;
}
extern void spi_dump(void);
void spi_write_data_dma(unsigned short* data,unsigned int sum_pixel,unsigned int data_bits,unsigned short line_num)
{
int i,ret;
unsigned int actual_flags = 0;
struct s_spi_ctx* spi_ctx=spi_get_interface();
if((data_bits <1) || (data_bits >31))
return;
switch (spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
REG32(SSP2_BASE_ADDRESS) = 0x261e0; // disable spi
REG32(SSP2_BASE_ADDRESS + 0x4) = 0x20d07;
REG32(SSP2_BASE_ADDRESS) = 0x261e1; // enable spi start trancemit
break;
case SPI_CONETROLER_0:
REG32(SSP0_BASE_ADDRESS) = 0x261e0; // disable spi
REG32(SSP0_BASE_ADDRESS + 0x4) = 0x20d07;
REG32(SSP0_BASE_ADDRESS) = 0x261e1; // enable spi start trancemit
break;
default:
LCDLOGE("spi enable failed");
break;
}
//2023410 add在每次spi dma数据传输请求前清除DMA中断标志
quec_rtos_flag_release(g_lcd_interrupt_flag,0,OSA_FLAG_AND);
spi_dma_transfer_request(spi_tx,data,sum_pixel);
//spi_dump();
i = 0;
while(i < 10) {
ret = quec_rtos_flag_wait(g_lcd_interrupt_flag, SPI_INTER_FLAG_FRAMEDONE, QUEC_FLAG_OR_CLEAR,
&actual_flags, 20);
if ((ret == OS_SUCCESS) && (0 != (actual_flags & SPI_INTER_FLAG_FRAMEDONE))){
dma_tx_complete = 0;
break;
}else{
LCDLOGE("####wait to finish (0x%x)(%d)!\n", actual_flags, i);
}
i++;
}
if(i>= 10 && (0 == (actual_flags & SPI_INTER_FLAG_FRAMEDONE))){
LCDLOGE("got dma done timeout!");
}
}
void spi_dump(void)
{
unsigned int i = 0;
for(i=0;i<12;i++)
{
LCDLOGI("--------SPI0a start dump----------\r\n");
LCDLOGI("SPI0a offset: 0x%x, value:0x%lx\r\n",i*4, REG32(SSP0_BASE_ADDRESS + i*4));
}
LCDLOGI("SPI0a offset: 0x54, value:0x%lx\r\n", REG32(SSP0_BASE_ADDRESS + 0x54));
LCDLOGI("--------SPI0 start dump end----------\r\n");
LCDLOGI("--------dmareg CSR031(DCSR)----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 4*DMA_DEV_LCD_TX_CH));
LCDLOGI("--------dmareg ALGN----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 0xa0));
LCDLOGI("--------dmareg INT----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 0xf0));
LCDLOGI("--------dmareg DRCMR1(RCMR)----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 0x100+4*DMA_REQ_SSP0_TX));
LCDLOGI("--------dmareg DSADR(DSADR)----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 0x204+16*DMA_DEV_LCD_TX_CH));
LCDLOGI("--------dmareg DTADR(DTADR)----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 0x208+16*DMA_DEV_LCD_TX_CH));
LCDLOGI("--------dmareg DCMD(DCMD)----------0x%x\r\n",REG32(DMA_BASE_ADDRESS + 0x20C+16*DMA_DEV_LCD_TX_CH));
}
void spi_set_clk_rate(unsigned int clk_dev)
{
struct s_spi_ctx* spi_ctx=spi_get_interface();
if(clk_dev >= SPI_CLK_LIMIT)
return;
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
REG32(APB_SSP2_CLK_RST) = 0x3|(clk_dev << 4);
break;
case SPI_CONETROLER_0:
REG32(APB_SSP0_CLK_RST) = 0x3|(clk_dev << 4);
break;
default:
LCDLOGE("set spi clk") ;
break;
}
}
int spi_lcd_init(unsigned char controler)
{
unsigned ssp_top_cfg, ssp_fifo_cfg, ssp_int_en_cfg, ssp_to_cfg;
struct s_spi_ctx* spi_ctx=spi_get_interface();
LCDLOGD("++++++++spi controler:%d,%d",spi_ctx->info.device_id,controler);
int ret = 0;
switch(controler)
{
case SPI_CONETROLER_1:
REG32(APB_SSP2_CLK_RST) = 0x7;
spi_set_clk_rate(SPI_812_5k);
ssp_top_cfg = 0x4d00;
ssp_fifo_cfg = 0x200e7;
ssp_int_en_cfg = 0xf;
ssp_to_cfg = 0x200;
REG32(SSP2_BASE_ADDRESS + 0) = ssp_top_cfg;
REG32(SSP2_BASE_ADDRESS + 0x4) = ssp_fifo_cfg;
REG32(SSP2_BASE_ADDRESS + 0x8) = ssp_int_en_cfg;
REG32(SSP2_BASE_ADDRESS + 0xc) = ssp_to_cfg;
REG32(SSP2_BASE_ADDRESS + 0) = ssp_top_cfg|0x1;
ret = 0;
break;
case SPI_CONETROLER_0:
REG32(APB_SSP0_CLK_RST) = 0x7;
spi_set_clk_rate(SPI_812_5k);
ssp_top_cfg = 0x4100;
ssp_fifo_cfg = 0x200e7;
ssp_int_en_cfg = 0xf;
ssp_to_cfg = 0x200;
REG32(SSP0_BASE_ADDRESS + 0) = ssp_top_cfg;
REG32(SSP0_BASE_ADDRESS + 0x4) = ssp_fifo_cfg;
REG32(SSP0_BASE_ADDRESS + 0x8) = ssp_int_en_cfg;
REG32(SSP0_BASE_ADDRESS + 0xc) = ssp_to_cfg;
REG32(SSP0_BASE_ADDRESS + 0) = ssp_top_cfg|0x1;
ret = 0;
break;
default:
ret = -1;
break;
}
return ret;
}
void ssp_write_cmd_data_to_LCD(unsigned int cmd, unsigned int data,unsigned int data_bits,unsigned short line_num)
{
int reg;
if((data_bits <1) || (data_bits >31))
return;
struct s_spi_ctx* spi_ctx=spi_get_interface();
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
REG32(SSP2_BASE_ADDRESS + 0x54) = 0x5; //master output
reg = REG32(SSP2_BASE_ADDRESS) & ~(0x1f << 5);
if(line_num == 3)
{
REG32(SSP2_BASE_ADDRESS) = reg | (data_bits << 5); //9 bit
if(!cmd)
{
*(volatile unsigned int*)(SSP2_BASE_ADDRESS + SSP_DATAR) = data;
}
else
{
*(volatile unsigned int*)(SSP2_BASE_ADDRESS + SSP_DATAR) = (1<< data_bits) | data;
}
}
else if(line_num == 4)
{
REG32(SSP2_BASE_ADDRESS) = reg | ((data_bits -1) << 5); //sent bit
*(volatile unsigned int*)(SSP2_BASE_ADDRESS + SSP_DATAR) = data;
}
else
LCDLOGE("ERROR: spi line number error!\r\n");
break;
case SPI_CONETROLER_0:
REG32(SSP0_BASE_ADDRESS + 0x54) = 0x5; //master output
reg = REG32(SSP0_BASE_ADDRESS) & ~(0x1f << 5);
if(line_num == 3)
{
REG32(SSP0_BASE_ADDRESS) = reg | (data_bits << 5); //9 bit
if(!cmd)
{
*(volatile unsigned int*)(SSP0_BASE_ADDRESS + SSP_DATAR) = data;
}
else
{
*(volatile unsigned int*)(SSP0_BASE_ADDRESS + SSP_DATAR) = (1<< data_bits) | data;
}
}
else if(line_num == 4)
{
REG32(SSP0_BASE_ADDRESS) = reg | ((data_bits -1) << 5); //sent bit
*(volatile unsigned int*)(SSP0_BASE_ADDRESS + SSP_DATAR) = data;
}
else
LCDLOGE("ERROR: spi line number error!\r\n");
break;
default:
LCDLOGE(" spi write error\r\n");
break;
}
}
void ssp_write_data_to_LCD_Gram(unsigned short* data,unsigned int sum_pixel,unsigned int data_bits,unsigned short line_num)
{
int reg;
int cnt,i;
if((data_bits <1) || (data_bits >31))
return;
struct s_spi_ctx* spi_ctx=spi_get_interface();
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
REG32(SSP2_BASE_ADDRESS + 0x54) = 0x5; //master output
reg = REG32(SSP2_BASE_ADDRESS) & ~(0x1f << 5);
if(line_num == 3)
REG32(SSP2_BASE_ADDRESS) = reg | (8 << 5); //
else if(line_num == 4)
REG32(SSP2_BASE_ADDRESS) = reg | ((data_bits -1) << 5); //
for(i=0;i<sum_pixel;i++)
{
cnt = 0;
while(!(REG32(SSP2_BASE_ADDRESS + SSP__STATUS) & (0x1 << 6))) //wait for tx not full
{
if(cnt++ > 1000000)
{
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
if(line_num == 3)
{
if((data_bits == 16) || (data_bits == 8))
{
*(volatile unsigned int*)(SSP2_BASE_ADDRESS + SSP_DATAR) = (1<< 8) | (*(data+i) >> 8);
cnt = 0;
while(!(REG32(SSP2_BASE_ADDRESS + SSP__STATUS) & (0x1 << 6))) //wait for tx not full
{
if(cnt++ > 1000000)
{
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
*(volatile unsigned int*)(SSP2_BASE_ADDRESS + SSP_DATAR) = (1<< 8) | (*(data+i) & 0xff);
}
else
LCDLOGE("spi write byte not support length!\r\n");
}
else if(line_num == 4)
*(volatile unsigned int*)(SSP2_BASE_ADDRESS + SSP_DATAR) = *(data+i);
else
{
LCDLOGE("ERROR: spi line number error!\r\n");
return;
}
}
break;
case SPI_CONETROLER_0:
REG32(SSP0_BASE_ADDRESS + 0x54) = 0x5; //master output
reg = REG32(SSP0_BASE_ADDRESS) & ~(0x1f << 5);
if(line_num == 3)
REG32(SSP0_BASE_ADDRESS) = reg | (8 << 5); //
else if(line_num == 4)
REG32(SSP0_BASE_ADDRESS) = reg | ((data_bits -1) << 5); //
for(i=0;i<sum_pixel;i++)
{
cnt = 0;
while(!(REG32(SSP0_BASE_ADDRESS + SSP__STATUS) & (0x1 << 6))) //wait for tx not full
{
if(cnt++ > 1000000)
{
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
if(line_num == 3)
{
if((data_bits == 16) || (data_bits == 8))
{
*(volatile unsigned int*)(SSP0_BASE_ADDRESS + SSP_DATAR) = (1<< 8) | (*(data+i) >> 8);
cnt = 0;
while(!(REG32(SSP0_BASE_ADDRESS + SSP__STATUS) & (0x1 << 6))) //wait for tx not full
{
if(cnt++ > 1000000)
{
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
*(volatile unsigned int*)(SSP0_BASE_ADDRESS + SSP_DATAR) = (1<< 8) | (*(data+i) & 0xff);
}
else
LCDLOGE("spi write byte not support length!\r\n");
}
else if(line_num == 4)
*(volatile unsigned int*)(SSP0_BASE_ADDRESS + SSP_DATAR) = *(data+i);
else
{
LCDLOGE("ERROR: spi line number error!\r\n");
return;
}
}
break;
default:
LCDLOGE(" spi write error\r\n");
break;
}
}
void ssp_read_data_from_LCD(unsigned int *data, unsigned int data_bits)
{
int status = 0;
unsigned reg = 0;
struct s_spi_ctx* spi_ctx=spi_get_interface();
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
reg = REG32(SSP2_BASE_ADDRESS) & ~(0x1f << 5);
if((data_bits <1) || (data_bits >31))
return;
if(data_bits >8)
REG32(SSP2_BASE_ADDRESS) = reg | (data_bits << 5);
else
REG32(SSP2_BASE_ADDRESS) = reg | ((data_bits -1) << 5); //8 bit
REG32(SSP2_BASE_ADDRESS+0x54) = 0x7; //master input
REG32(SSP2_BASE_ADDRESS + SSP_DATAR) = 0x00; //dummy read
while(((status = REG32(SSP2_BASE_ADDRESS + SSP__STATUS)) & (0x1 << 14)) == 0);
*data = REG32(SSP2_BASE_ADDRESS +SSP_DATAR);
break;
case SPI_CONETROLER_0:
reg = REG32(SSP0_BASE_ADDRESS) & ~(0x1f << 5);
if((data_bits <1) || (data_bits >31))
return;
if(data_bits >8)
REG32(SSP0_BASE_ADDRESS) = reg | (data_bits << 5);
else
REG32(SSP0_BASE_ADDRESS) = reg | ((data_bits -1) << 5); //8 bit
REG32(SSP0_BASE_ADDRESS+0x54) = 0x7; //master input
REG32(SSP0_BASE_ADDRESS + SSP_DATAR) = 0x00; //dummy read
while(((status = REG32(SSP0_BASE_ADDRESS + SSP__STATUS)) & (0x1 << 14)) == 0);
*data = REG32(SSP0_BASE_ADDRESS +SSP_DATAR);
break;
default:
LCDLOGE(" spi read error\r\n");
break;
}
}
void wait_ssp_write_data_to_LCD_complete(void)
{
int cnt = 0;
struct s_spi_ctx* spi_ctx=spi_get_interface();
switch(spi_ctx->info.device_id)
{
case SPI_CONETROLER_1:
while((REG32(SSP2_BASE_ADDRESS + SSP__STATUS) & 0xfc0) != 0x40) //wait for tx empty
{
if(cnt++ > 1000000)
{
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
break;
case SPI_CONETROLER_0:
while((REG32(SSP0_BASE_ADDRESS + SSP__STATUS) & 0xfc0) != 0x40) //wait for tx empty
{
if(cnt++ > 1000000)
{
LCDLOGE("ERROR: spi write byte error!\r\n");
return;
}
}
break;
default:
LCDLOGE("port error\r\n");
break;
}
}
/*spi 3wire 1data lane 1interface function*/
unsigned int mfp_cfg_lcd_spi_3w_1l_1if[] = {
MFP_REG(QUEC_LCD_SPI_CS_NUM ) | QUEC_LCD_SPI_CS_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*CS*/
MFP_REG(QUEC_LCD_SPI_RST_NUM ) | QUEC_LCD_SPI_RST_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*RST*/
MFP_REG(QUEC_LCD_SPI_SCLK_NUM ) | QUEC_LCD_SPI_SCLK_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*SCLK*/
MFP_REG(QUEC_LCD_SPI_SDA_NUM ) | QUEC_LCD_SPI_SDA_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*SDA*/
MFP_EOC
};
/*spi 4wire 1data lane 1interface function*/
unsigned int mfp_cfg_lcd_spi_4w_1l_1if[] = {
MFP_REG(QUEC_LCD_SPI_CS_NUM ) | QUEC_LCD_SPI_CS_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*CS*/
MFP_REG(QUEC_LCD_SPI_RST_NUM ) | QUEC_LCD_SPI_RST_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*RST*/
MFP_REG(QUEC_LCD_SPI_SCLK_NUM ) | QUEC_LCD_SPI_SCLK_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*SCLK*/
MFP_REG(QUEC_LCD_SPI_SDA_NUM ) | QUEC_LCD_SPI_SDA_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*SDA*/
MFP_REG(QUEC_LCD_SPI_DCX_NUM ) | QUEC_LCD_SPI_DCX_AF | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE, /*DCX*/
MFP_EOC
};
void LCD_Pinmuxcfg(unsigned int interface)
{
LCDLOGI("pin:%d\r\n",interface);
switch(interface){
case 0: /*spi_3wire_1datalane_1if*/
mfp_config(mfp_cfg_lcd_spi_3w_1l_1if);
break;
case 1: /*spi_3wire_2datalane_1if*/
break;
case 2: /*spi_3wire_1datalane_2if*/
break;
case 3: /*spi_3wire_2datalane_2if*/
break;
case 4: /*spi_4wire_1datalane_1if*/
mfp_config(mfp_cfg_lcd_spi_4w_1l_1if);
break;
case 5: /*spi_4wire_1datalane_2if*/
break;
default:/*Invalid case*/
;
}
}
void spi_set_cs_high(void)
{
GpioSetDirection(SPI_LCD_CS,GPIO_OUT_PIN);
GpioSetLevel(SPI_LCD_CS,GPIORC_HIGH);
}
void spi_set_cs_low(void)
{
GpioSetDirection(SPI_LCD_CS,GPIO_OUT_PIN);
GpioSetLevel(SPI_LCD_CS,GPIORC_LOW);
}
void spi_uninit(struct s_spi_ctx *spi_ctx)
{
spi_ctx->status = SPI_STATUS_UNINIT;
return;
}
void spi_reset(struct s_spi_ctx *spi_ctx)
{
return;
}
void lcd_spi_set_data_mode(void)
{
GpioSetDirection(SPI_LCD_DCX , GPIO_OUT_PIN);
GpioSetLevel(SPI_LCD_DCX ,GPIORC_HIGH);
}
void lcd_spi_set_cmd_mode(void)
{
GpioSetDirection(SPI_LCD_DCX , GPIO_OUT_PIN);
GpioSetLevel(SPI_LCD_DCX ,GPIORC_LOW);
}
int spi_write_cmd(struct s_spi_ctx *spi_ctx, unsigned int cmd, unsigned int bits)
{
struct spi_info *spi = &(spi_ctx->info);
spi_set_clk_rate(spi->timing->wclk);
if(4 == spi->line_num)
{
lcd_spi_set_cmd_mode();
}
spi_set_cs_low();
ssp_write_cmd_data_to_LCD(0,cmd,bits,spi->line_num);
wait_ssp_write_data_to_LCD_complete();
panel_delay(1);
spi_set_cs_high();
return 0;
}
int spi_write_data(struct s_spi_ctx *spi_ctx, unsigned int data, unsigned int bits)
{
struct spi_info *spi = &(spi_ctx->info);
spi_set_clk_rate(spi->timing->wclk);
if(4 == spi->line_num)
{
lcd_spi_set_data_mode();
}
spi_set_cs_low();
ssp_write_cmd_data_to_LCD(1,data,bits,spi->line_num);
wait_ssp_write_data_to_LCD_complete();
panel_delay(1);
spi_set_cs_high();
return 0;
}
int spi_read_data(struct s_spi_ctx *spi_ctx, unsigned int cmd, unsigned int cmd_bits,
unsigned int *data, unsigned int data_bits)
{
struct spi_info *spi = &(spi_ctx->info);
if(4 == spi->line_num)
{
lcd_spi_set_cmd_mode();
}
spi_set_clk_rate(spi->timing->rclk);
spi_set_cs_low();
ssp_write_cmd_data_to_LCD(0,cmd,cmd_bits,spi->line_num);
panel_delay(10);
ssp_read_data_from_LCD(data,data_bits);
spi_set_cs_high();
return 0;
}
struct s_spi_ctx* spi_init(unsigned int sclk, struct spi_info *info, int work_mode)
{
int ret = 0;
struct s_spi_ctx* spi_ctx = &g_spi_ctx;
int i;
LCDLOGD("( dev_id:%d)+++",info->device_id);
if(info == NULL || info->timing == NULL){
LCDLOGE("Invalid param!");
return NULL;
}
if((info->format != SPI_FORMAT_RGB565) &&
(info->format != SPI_FORMAT_RGB666) && (info->data_lane_num == 1)){
LCDLOGE("Format error!");
return NULL;
}
spi_ctx->cur_path = 0;
spi_ctx->cur_cs = 0;
spi_ctx->status = 0;
spi_ctx->base_addr = 0;
spi_ctx->sclk = sclk;
spi_ctx->info.line_num = info->line_num;
spi_ctx->info.interface_id = info->interface_id;
spi_ctx->info.data_lane_num = info->data_lane_num;
spi_ctx->info.format = info->format;
spi_ctx->info.device_id = info->device_id; /*spi控制器*/
spi_ctx->info.sample_edge = info->sample_edge;
spi_ctx->info.force_cs = info->force_cs;
spi_ctx->info.endian = info->endian;
spi_ctx->info.timing = info->timing;
spi_ctx->work_mode = work_mode;
ret = spi_lcd_init(info->device_id);
if(ret != 0)
{
LCDLOGE("spi initialize failed");
}
if(work_mode == SPI_WORK_MODE_DMA){
spi_dma_init();
}
spi_ctx->status = SPI_STATUS_INIT;
return spi_ctx;
}
int spi_update(struct s_spi_ctx *spi_ctx, int work_mode)
{
LCDLOGI("spi_update +++\r\n");
spi_ctx->work_mode = work_mode;
LCDLOGI("spi_update ----\r\n");
return 0;
}