Files

1667 lines
54 KiB
C
Executable File

/*
* spi-infinity.c- Sigmastar
*
* Copyright (C) 2018 Sigmastar Technology Corp.
*
* Author: richard.guo <richard.guo@sigmastar.com.tw>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "MsTypes.h"
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include "../../gpio/infinity2m/padmux.h"
#include "../../gpio/drvGPIO.h"
/*-------------------------------------------------------------------------------------------------
* padmux:
* mode=1: PAD_PM_SD_CDZ,PAD_SD_D1,PAD_SD_D0,PAD_SD_CLK,PAD_SD_CMD
* mode=2: PAD_TTL16,PAD_TTL17,PAD_TTL18,PAD_TTL19
* mode=3: PAD_GPIO4,PAD_GPIO5,PAD_GPIO6,PAD_GPIO7
* mode=4: PAD_FUART_RX,PAD_FUART_TX,PAD_FUART_CTS,PAD_FUART_RTS
* mode=5: PAD_GPIO8,PAD_GPIO9,PAD_GPIO10,PAD_GPIO11
* mode=6: PAD_GPIO0,PAD_GPIO1,PAD_GPIO2,PAD_GPIO3
-------------------------------------------------------------------------------------------------
*/
#define MSPI0_PADMUX_MODE 5
char padmux_mode[] = {0, PINMUX_FOR_SPI0_MODE_1,PINMUX_FOR_SPI0_MODE_2,PINMUX_FOR_SPI0_MODE_3,
PINMUX_FOR_SPI0_MODE_4,PINMUX_FOR_SPI0_MODE_5,PINMUX_FOR_SPI0_MODE_6
};
//-------------------------------------------------------------------------------------------------
// Global Variables
//-------------------------------------------------------------------------------------------------
static bool gbInitFlag = false;
static bool SUPPORT_DMA = true;
#define mutex_init(arg)
#define mutex_lock(arg)
#define mutex_unlock(arg)
#define spi_device spi_slave
#define to_ss_spi_slave(s) container_of(s, struct mstar_spi, slave)
struct spi_transfer {
const void * tx_buf;
void * rx_buf;
unsigned len;
};
//-------------------------------------------------------------------------------------------------
// RegbaseAddr Disc
//-------------------------------------------------------------------------------------------------
#define mspi_dbg 0
#if mspi_dbg == 1
#define mspi_dbgmsg(args...) printf(args)
#define DEBUG_MSPI(args...) printf(args)
#else
#define mspi_dbgmsg(args...) do{}while(0)
#define DEBUG_MSPI(args...) { }
#endif
#define mspi_errmsg(args...) printf(args)
#define mspi_infomsg(args...) printf(args)
#define BOOL bool
#define SUPPORT_SPI_1 0
#define BANK_TO_ADDR32(b) (b<<9)
#define BANK_SIZE 0x200
#define MS_BASE_REG_RIU_PA 0x1F000000
#define MSPI0_BANK_ADDR 0x1110
#define MSPI1_BANK_ADDR 0x1111
#define CLK__BANK_ADDR 0x1038
#define CHIPTOP_BANK_ADDR 0x101E
#define MOVDMA_BANK_ADDR 0x100B
#define BASE_REG_MSPI0_ADDR MSPI0_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111000)
#define BASE_REG_MSPI1_ADDR MSPI1_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111100)
#define BASE_REG_CLK_ADDR CLK__BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x103800)
#define BASE_REG_CHIPTOP_ADDR CHIPTOP_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
#define BASE_REG_MOVDMA_ADDR MOVDMA_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
//-------------------------------------------------------------------------------------------------
// Hardware Register Capability
//-------------------------------------------------------------------------------------------------
#define MSPI_WRITE_BUF_OFFSET 0x40
#define MSPI_READ_BUF_OFFSET 0x44
#define MSPI_WBF_SIZE_OFFSET 0x48
#define MSPI_RBF_SIZE_OFFSET 0x48
// read/ write buffer size
#define MSPI_RWSIZE_MASK 0xFF
#define MSPI_RSIZE_BIT_OFFSET 0x8
#define MAX_READ_BUF_SIZE 0x8
#define MAX_WRITE_BUF_SIZE 0x8
// CLK config
#define MSPI_CTRL_OFFSET 0x49
#define MSPI_CLK_CLOCK_OFFSET 0x49
#define MSPI_CLK_CLOCK_BIT_OFFSET 0x08
#define MSPI_CLK_CLOCK_MASK 0xFF
#define MSPI_CLK_PHASE_MASK 0x40
#define MSPI_CLK_PHASE_BIT_OFFSET 0x06
#define MSPI_CLK_POLARITY_MASK 0x80
#define MSPI_CLK_POLARITY_BIT_OFFSET 0x07
#define MSPI_CLK_PHASE_MAX 0x1
#define MSPI_CLK_POLARITY_MAX 0x1
#define MSPI_CLK_CLOCK_MAX 0x7
// DC config
#define MSPI_DC_MASK 0xFF
#define MSPI_DC_BIT_OFFSET 0x08
#define MSPI_DC_TR_START_OFFSET 0x4A
#define MSPI_DC_TRSTART_MAX 0xFF
#define MSPI_DC_TR_END_OFFSET 0x4A
#define MSPI_DC_TREND_MAX 0xFF
#define MSPI_DC_TB_OFFSET 0x4B
#define MSPI_DC_TB_MAX 0xFF
#define MSPI_DC_TRW_OFFSET 0x4B
#define MSPI_DC_TRW_MAX 0xFF
// Frame Config
#define MSPI_FRAME_WBIT_OFFSET 0x4C
#define MSPI_FRAME_RBIT_OFFSET 0x4E
#define MSPI_FRAME_BIT_MAX 0x07
#define MSPI_FRAME_BIT_MASK 0x07
#define MSPI_FRAME_BIT_FIELD 0x03
#define MSPI_LSB_FIRST_OFFSET 0x50
#define MSPI_TRIGGER_OFFSET 0x5A
#define MSPI_DONE_OFFSET 0x5B
#define MSPI_DONE_CLEAR_OFFSET 0x5C
#define MSPI_CHIP_SELECT_OFFSET 0x5F
#define MSPI_FULL_DEPLUX_RD00 (0x78)
#define MSPI_FULL_DEPLUX_RD01 (0x78)
#define MSPI_FULL_DEPLUX_RD02 (0x79
#define MSPI_FULL_DEPLUX_RD03 (0x79)
#define MSPI_FULL_DEPLUX_RD04 (0x7a)
#define MSPI_FULL_DEPLUX_RD05 (0x7a)
#define MSPI_FULL_DEPLUX_RD06 (0x7b)
#define MSPI_FULL_DEPLUX_RD07 (0x7b)
#define MSPI_FULL_DEPLUX_RD08 (0x7c)
#define MSPI_FULL_DEPLUX_RD09 (0x7c)
#define MSPI_FULL_DEPLUX_RD10 (0x7d)
#define MSPI_FULL_DEPLUX_RD11 (0x7d)
#define MSPI_FULL_DEPLUX_RD12 (0x7e)
#define MSPI_FULL_DEPLUX_RD13 (0x7e)
#define MSPI_FULL_DEPLUX_RD14 (0x7f)
#define MSPI_FULL_DEPLUX_RD15 (0x7f)
//chip select bit map
#define MSPI_CHIP_SELECT_MAX 0x07
// control bit
#define MSPI_DONE_FLAG 0x01
#define MSPI_TRIGGER 0x01
#define MSPI_CLEAR_DONE 0x01
#define MSPI_INT_ENABLE 0x04
#define MSPI_RESET 0x02
#define MSPI_ENABLE 0x01
//clkgen reg bank
// clk_mspi0
#define MSPI0_CLK_CFG 0x33//bit 2 ~bit 3
#define MSPI0_CLK_108M 0x00
#define MSPI0_CLK_54M 0x04
#define MSPI0_CLK_12M 0x08
#define MSPI0_CLK_MASK 0x0F
#define MSPI0_CLKGATE_MASK 0x01
// clk_mspi1
#define MSPI1_CLK_CFG 0x33 //bit 10 ~bit 11
#define MSPI1_CLK_108M 0x0000
#define MSPI1_CLK_54M 0x0400
#define MSPI1_CLK_12M 0x0800
#define MSPI1_CLK_MASK 0x0F00
#define MSPI1_CLKGATE_MASK 0x0100
// clk_mspi
#define MSPI_CLK_CFG 0x33
#define MSPI_SELECT_0 0x0000
#define MSPI_SELECT_1 0x4000
#define MSPI_CLK_MASK 0xF000
//CHITOP 101E mspi mode select
#define MSPI0_MODE 0x0C //bit0~bit1
#define MSPI0_MODE_MASK 0x07
#define MSPI1_MODE 0x0C //bit4~bit5
#define MSPI1_MODE_MASK 0x70
#define EJTAG_MODE 0xF
#define EJTAG_MODE_1 0x01
#define EJTAG_MODE_2 0x02
#define EJTAG_MODE_3 0x03
#define EJTAG_MODE_MASK 0x03
//MOVDMA 100B
#define MOV_DMA_SRC_ADDR_L 0x03
#define MOV_DMA_SRC_ADDR_H 0x04
#define MOV_DMA_DST_ADDR_L 0x05
#define MOV_DMA_DST_ADDR_H 0x06
#define MOV_DMA_BYTE_CNT_L 0x07
#define MOV_DMA_BYTE_CNT_H 0x08
#define DMA_MOVE0_IRQ_CLR 0x28
#define MOV_DMA_IRQ_FINAL_STATUS 0x2A
#define DMA_MOVE0_ENABLE 0x00
#define DMA_RW 0x50 //0 for dma write to device, 1 for dma read from device
#define DMA_READ 0x01
#define DMA_WRITE 0x00
#define DMA_DEVICE_MODE 0x51
#define DMA_DEVICE_SEL 0x52
//spi dma
#define MSPI_DMA_DATA_LENGTH_L 0x30
#define MSPI_DMA_DATA_LENGTH_H 0x31
#define MSPI_DMA_ENABLE 0x32
#define MSPI_DMA_RW_MODE 0x33
#define MSPI_DMA_WRITE 0x00
#define MSPI_DMA_READ 0x01
//-------------------------------------------------------------------------------------------------
// Local Defines
//-------------------------------------------------------------------------------------------------
#define READ_BYTE(_reg) (*(volatile u8*)(_reg))
#define READ_WORD(_reg) (*(volatile u16*)(_reg))
#define READ_LONG(_reg) (*(volatile u32*)(_reg))
#define WRITE_BYTE(_reg, _val) {(*((volatile u8*)(_reg))) = (u8)(_val); }
#define WRITE_WORD(_reg, _val) {(*((volatile u16*)(_reg))) = (u16)(_val); }
#define WRITE_LONG(_reg, _val) {(*((volatile u32*)(_reg))) = (u32)(_val); }
#define WRITE_WORD_MASK(_reg, _val, _mask) {(*((volatile u16*)(_reg))) = ((*((volatile u16*)(_reg))) & ~(_mask)) | ((u16)(_val) & (_mask)); }
// read 2 byte
#define MSPI_READ(_reg_) READ_WORD(bs->VirtMspBaseAddr + ((_reg_)<<2))
// write 2 byte
#define MSPI_WRITE(_reg_, _val_) WRITE_WORD(bs->VirtMspBaseAddr + ((_reg_)<<2), (_val_))
//write 2 byte mask
#define MSPI_WRITE_MASK(_reg_, _val_, mask) WRITE_WORD_MASK(bs->VirtMspBaseAddr + ((_reg_)<<2), (_val_), (mask))
#define CLK_READ(_reg_) READ_WORD(bs->VirtClkBaseAddr + ((_reg_)<<2))
#define CLK_WRITE(_reg_, _val_) WRITE_WORD(bs->VirtClkBaseAddr + ((_reg_)<<2), (_val_))
#define CLK_WRITE_MASK(_reg_, _val_, mask) WRITE_WORD_MASK(bs->VirtClkBaseAddr + ((_reg_)<<2), (_val_), (mask))
#define CHIPTOP_READ(_reg_) READ_WORD(bs->VirtChiptopBaseAddr + ((_reg_)<<2))
#define CHIPTOP_WRITE(_reg_, _val_) WRITE_WORD(bs->VirtChiptopBaseAddr + ((_reg_)<<2), (_val_))
#define MOVDMA_READ(_reg_) READ_WORD(bs->VirtMovdmaBaseAddr + ((_reg_)<<2))
#define MOVDMA_WRITE(_reg_, _val_) WRITE_WORD(bs->VirtMovdmaBaseAddr + ((_reg_)<<2), (_val_))
#define _HAL_MSPI_ClearDone() MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET,MSPI_CLEAR_DONE)
#define MAX_CHECK_CNT 2000
#define MSPI_READ_INDEX 0x0
#define MSPI_WRITE_INDEX 0x1
#define SPI_MIU0_BUS_BASE 0x20000000
//-------------------------------------------------------------------------------------------------
// Local Variables
//-------------------------------------------------------------------------------------------------
typedef enum
{
E_MSPI0,
E_MSPI1,
E_MSPI_MAX,
}MSPI_CH;
typedef enum
{
E_MSPI_BIT_MSB_FIRST,
E_MSPI_BIT_LSB_FIRST,
}MSPI_BitSeq_e;
typedef enum _HAL_CLK_Config
{
E_MSPI_POL,
E_MSPI_PHA,
E_MSPI_CLK
}eCLK_config;
typedef enum _HAL_DC_Config
{
E_MSPI_TRSTART,
E_MSPI_TREND,
E_MSPI_TB,
E_MSPI_TRW
}eDC_config;
typedef struct
{
u32 u32Clock;
u8 u8Clock;
bool BClkPolarity;
bool BClkPhase;
u32 u32MAXClk;
} MSPI_CLKConfig;
typedef struct
{
u8 u8ClkSpi_cfg;
u8 u8ClkSpi_DIV;
u32 u32ClkSpi;
}ST_DRV_MSPI_CLK;
typedef enum
{
E_MSPI_DBGLV_NONE, //disable all the debug message
E_MSPI_DBGLV_INFO, //information
E_MSPI_DBGLV_NOTICE, //normal but significant condition
E_MSPI_DBGLV_WARNING, //warning conditions
E_MSPI_DBGLV_ERR, //error conditions
E_MSPI_DBGLV_CRIT, //critical conditions
E_MSPI_DBGLV_ALERT, //action must be taken immediately
E_MSPI_DBGLV_EMERG, //system is unusable
E_MSPI_DBGLV_DEBUG, //debug-level messages
} MSPI_DbgLv;
typedef enum _MSPI_ERRORNOn {
E_MSPI_OK = 0
,E_MSPI_INIT_FLOW_ERROR =1
,E_MSPI_DCCONFIG_ERROR =2
,E_MSPI_CLKCONFIG_ERROR =4
,E_MSPI_FRAMECONFIG_ERROR =8
,E_MSPI_OPERATION_ERROR = 0x10
,E_MSPI_PARAM_OVERFLOW = 0x20
,E_MSPI_MMIO_ERROR = 0x40
,E_MSPI_HW_NOT_SUPPORT = 0x80
,E_MSPI_NULL
} MSPI_ErrorNo;
typedef struct
{
MSPI_CH eCurrentCH;
char *VirtMspBaseAddr;
char *VirtClkBaseAddr;
char *VirtChiptopBaseAddr;
char *VirtMovdmaBaseAddr;
} MSPI_BaseAddr_st;
static MSPI_BaseAddr_st _hal_msp = {
.eCurrentCH = E_MSPI0,
//.VirtMspBaseAddr = BASE_REG_MSPI0_ADDR,
//.VirtClkBaseAddr = BASE_REG_CLK_ADDR,
//.VirtChiptopBaseAddr = BASE_REG_CHIPTOP_ADDR,
};
typedef enum {
E_MSPI_MODE0, //CPOL = 0,CPHA =0
E_MSPI_MODE1, //CPOL = 0,CPHA =1
E_MSPI_MODE2, //CPOL = 1,CPHA =0
E_MSPI_MODE3, //CPOL = 1,CPHA =1
E_MSPI_MODE_MAX,
} MSPI_Mode_Config_e;
typedef struct
{
u8 u8TrStart; //time from trigger to first SPI clock
u8 u8TrEnd; //time from last SPI clock to transferred done
u8 u8TB; //time between byte to byte transfer
u8 u8TRW; //time between last write and first read
} MSPI_DCConfig;
typedef struct
{
u8 u8WBitConfig[8]; //bits will be transferred in write buffer
u8 u8RBitConfig[8]; //bits Will be transferred in read buffer
} MSPI_FrameConfig;
#define MSTAR_SPI_TIMEOUT_MS 30000
#define MSTAR_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA /*| SPI_CS_HIGH | SPI_NO_CS | SPI_LSB_FIRST*/)
#define DRV_NAME "spi"
struct mstar_spi {
struct spi_slave slave;
void __iomem *regs;
struct clk *clk;
int support_dma;
int xfer_w_dma;
const u8 *tx_buf;
u8 *rx_buf;
int len;
char *VirtMspBaseAddr;
char *VirtClkBaseAddr;
char *VirtChiptopBaseAddr;
char *VirtMovdmaBaseAddr;
char u8channel;
u32 u32pad_mode;
u32 spi_mode;
u32 max_speed_hz;
u8 bits_per_word;
};
static void _HAL_MSPI_CheckandSetBaseAddr(MSPI_CH eChannel)
{
#if 0
if(eChannel == _hal_msp.eCurrentCH)
{
return;
} else if(eChannel == E_MSPI0)
{
_hal_msp.eCurrentCH = E_MSPI0;
_hal_msp.VirtMspBaseAddr = BASE_REG_MSPI0_ADDR;
_hal_msp.VirtClkBaseAddr = BASE_REG_CLK_ADDR;
_hal_msp.VirtChiptopBaseAddr = BASE_REG_CHIPTOP_ADDR,
printk(KERN_ERR"[Lwc Debug] Set mspi0 base address : %x\n",_hal_msp.VirtMspBaseAddr);
printk(KERN_ERR"[Lwc Debug] Set clk base address : %x\n",_hal_msp.VirtClkBaseAddr);
} else if(eChannel == E_MSPI1)
{
_hal_msp.eCurrentCH = E_MSPI1;
_hal_msp.VirtMspBaseAddr = BASE_REG_MSPI1_ADDR;
_hal_msp.VirtClkBaseAddr = BASE_REG_CLK_ADDR;
_hal_msp.VirtChiptopBaseAddr = BASE_REG_CHIPTOP_ADDR,
printk(KERN_ERR"[Lwc Debug] Set mspi1 base address : %x\n",_hal_msp.VirtMspBaseAddr);
printk(KERN_ERR"[Lwc Debug] Set clk base address : %x\n",_hal_msp.VirtClkBaseAddr);
} else
{
//DEBUG_MSPI(E_MSPI_DBGLV_ERR,printk("[Mspi Error]FUN:%s MSPI Channel is out of range!\n",__FUNCTION__));
printk("[Mspi Error]FUN: MSPI Channel is out of range!\n");
return ;
}
#endif
}
//------------------------------------------------------------------------------
/// Description : Reset Frame register setting of MSPI
/// @param NONE
/// @return TRUE : reset complete
//------------------------------------------------------------------------------
BOOL HAL_MSPI_Reset_FrameConfig(struct mstar_spi *bs,MSPI_CH eChannel)
{
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
// Frame reset
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET, 0xFFF);
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET+2, 0xFFF);
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET, 0xFFF);
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET+2, 0xFFF);
mutex_unlock(&hal_mspi_lock);
return TRUE;
}
//------------------------------------------------------------------------------
/// Description : MSPI interrupt enable
/// @param bEnable \b OUT: enable or disable mspi interrupt
/// @return void:
//------------------------------------------------------------------------------
void HAL_MSPI_IntEnable(struct mstar_spi *bs,MSPI_CH eChannel,bool bEnable)
{
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr(eChannel);
if(bEnable) {
MSPI_WRITE(MSPI_CTRL_OFFSET,MSPI_READ(MSPI_CTRL_OFFSET)|MSPI_INT_ENABLE);
} else {
MSPI_WRITE(MSPI_CTRL_OFFSET,MSPI_READ(MSPI_CTRL_OFFSET)&(~MSPI_INT_ENABLE));
}
mutex_unlock(&hal_mspi_lock);
}
void HAL_MSPI_Init(struct mstar_spi *bs,MSPI_CH eChannel,u8 u8Mode)
{
u16 TempData;
//init MSP
//DEBUG_MSPI(E_MSPI_DBGLV_INFO,printk("HAL_MSPI_Init\n"));
mspi_dbgmsg("HAL_MSPI_Init : Channel=%d spi mode=%d\n",eChannel,u8Mode);
mutex_init(&hal_mspi_lock);
if((eChannel > E_MSPI1) || (u8Mode < 1))
{
mspi_errmsg("mspi 1 not supprted\n");
return;
}
else if((eChannel == E_MSPI0) && (u8Mode > 6))
{
mspi_errmsg("mspi pad mode must be 1~6\n");
return;
}
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr(eChannel);
MSPI_WRITE(MSPI_CTRL_OFFSET,MSPI_READ(MSPI_CTRL_OFFSET)|(MSPI_RESET|MSPI_ENABLE));
if(eChannel == E_MSPI0)
{
// CLK SETTING
TempData = CLK_READ(MSPI0_CLK_CFG);
TempData &= ~(MSPI0_CLK_MASK);
TempData |= MSPI0_CLK_108M;
CLK_WRITE(MSPI0_CLK_CFG, TempData);
{
//printk("SPI: %d pad set by SPI driver!!\n", eChannel);
//select mspi mode
MDrv_GPIO_PadGroupMode_Set(padmux_mode[u8Mode]);
/*TempData = CHIPTOP_READ(MSPI0_MODE);
TempData &= ~(MSPI0_MODE_MASK);
TempData |= u8Mode;
CHIPTOP_WRITE(MSPI0_MODE,TempData);
//Disable jtag mode // IO PAD conflict turn off jtag
TempData = CHIPTOP_READ(EJTAG_MODE);
if((u8Mode == 4 && TempData == EJTAG_MODE_1) ||
(u8Mode == 3 && TempData == EJTAG_MODE_3) ){
TempData &= ~(EJTAG_MODE_MASK);
CHIPTOP_WRITE(EJTAG_MODE,TempData);
}*/
}
}
mutex_unlock(&hal_mspi_lock);
return;
}
//------------------------------------------------------------------------------
/// Description : config spi transfer timing
/// @param ptDCConfig \b OUT struct pointer of bits of buffer tranferred to slave config
/// @return NONE
//------------------------------------------------------------------------------
void HAL_MSPI_SetDcTiming (struct mstar_spi *bs,MSPI_CH eChannel, eDC_config eDCField, U8 u8DCtiming)
{
U16 u16TempBuf = 0;
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr(eChannel);
switch(eDCField) {
case E_MSPI_TRSTART:
u16TempBuf = MSPI_READ(MSPI_DC_TR_START_OFFSET);
u16TempBuf &= (~MSPI_DC_MASK);
u16TempBuf |= u8DCtiming;
MSPI_WRITE(MSPI_DC_TR_START_OFFSET, u16TempBuf);
break;
case E_MSPI_TREND:
u16TempBuf = MSPI_READ(MSPI_DC_TR_END_OFFSET);
u16TempBuf &= MSPI_DC_MASK;
u16TempBuf |= u8DCtiming << MSPI_DC_BIT_OFFSET;
MSPI_WRITE(MSPI_DC_TR_END_OFFSET, u16TempBuf);
break;
case E_MSPI_TB:
u16TempBuf = MSPI_READ(MSPI_DC_TB_OFFSET);
u16TempBuf &= (~MSPI_DC_MASK);
u16TempBuf |= u8DCtiming;
MSPI_WRITE(MSPI_DC_TB_OFFSET, u16TempBuf);
break;
case E_MSPI_TRW:
u16TempBuf = MSPI_READ(MSPI_DC_TRW_OFFSET);
u16TempBuf &= MSPI_DC_MASK;
u16TempBuf |= u8DCtiming << MSPI_DC_BIT_OFFSET;
MSPI_WRITE(MSPI_DC_TRW_OFFSET, u16TempBuf);
break;
}
mutex_unlock(&hal_mspi_lock);
}
static void _HAL_MSPI_RWBUFSize(struct mstar_spi *bs,BOOL Direct, U8 Size)
{
U16 u16Data = 0;
u16Data = MSPI_READ(MSPI_RBF_SIZE_OFFSET);
//printk("===RWBUFSize:%d\n",Size);
if(Direct == MSPI_READ_INDEX)
{
u16Data &= MSPI_RWSIZE_MASK;
u16Data |= Size << MSPI_RSIZE_BIT_OFFSET;
mspi_dbgmsg("MSPI_READ_INDEX: reg data=%d\n", u16Data);
}
else
{
u16Data &= ~MSPI_RWSIZE_MASK;
u16Data |= Size;
mspi_dbgmsg("MSPI_WRITE_INDEX: reg data=%d\n", u16Data);
}
MSPI_WRITE(MSPI_RBF_SIZE_OFFSET, u16Data);
// for test
mspi_dbgmsg("reg=0x%x, data=0x%x\n", MSPI_RBF_SIZE_OFFSET, u16Data);
}
//------------------------------------------------------------------------------
/// Description : check MSPI operation complete
/// @return TRUE : operation complete
/// @return FAIL : failed timeout
//------------------------------------------------------------------------------
static U16 _HAL_MSPI_CheckDone(struct mstar_spi *bs)
{
/*
U16 uCheckDoneCnt = 0;
U16 uDoneFlag = 0;
while(uCheckDoneCnt < MAX_CHECK_CNT) {
uDoneFlag = MSPI_READ(MSPI_DONE_OFFSET);
if(uDoneFlag & MSPI_DONE_FLAG) {
printk("Done flag success!!!!!!!!!!!!!!!!!!!!!!!!\n");
return TRUE;
}
// printk("...");
uCheckDoneCnt++;
}
//DEBUG_MSPI(E_MSPI_DBGLV_ERR,printk("ERROR:MSPI Operation Timeout!!!!!\n"));
printk("ERROR:MSPI Operation asasTimeout!!!!!\n");
return FALSE;
*/
return MSPI_READ(MSPI_DONE_OFFSET);
}
U32 HAL_MSPI_SelectCLK(struct mstar_spi *bs,U8 u8Channel) //Enable DMA CLK
{
u16 TempData;
TempData = CLK_READ(MSPI_CLK_CFG);
if(u8Channel == E_MSPI0)//mspi0
{
// CLK SETTING
TempData &= ~(MSPI_CLK_MASK);
TempData |= MSPI_SELECT_0;
}
else if(u8Channel == E_MSPI1)//mspi1
{
// CLK SETTING
TempData &= ~(MSPI_CLK_MASK);
TempData |= MSPI_SELECT_1;
}
CLK_WRITE(MSPI_CLK_CFG, TempData);
return 0;
}
//------------------------------------------------------------------------------
/// Description : Trigger MSPI operation
/// @return TRUE : operation success
/// @return FALSE : operation timeout
//------------------------------------------------------------------------------#define HW_MSPI_WAIT_TIMEOUT (30000)
#define HW_MSPI_WAIT_TIMEOUT (30000)
BOOL _HAL_MSPI_Trigger(struct mstar_spi *bs)
{
U16 volatile time_remain = HW_MSPI_WAIT_TIMEOUT;
// trigger operation
MSPI_WRITE(MSPI_TRIGGER_OFFSET,MSPI_TRIGGER);
while (time_remain--) {
if (_HAL_MSPI_CheckDone(bs) == 1) { //done
_HAL_MSPI_ClearDone(); // for debug
mspi_infomsg("<<<<<<<<<<<<<<<<<<< SPI_Done >>>>>>>>>>>>>>>>>\n");
if(bs->xfer_w_dma){ // clear MOVDMA irq
u16 intsrc = MOVDMA_READ(MOV_DMA_IRQ_FINAL_STATUS);
MOVDMA_WRITE(DMA_MOVE0_IRQ_CLR, intsrc);
}
break;
}
}
MSPI_WRITE(MSPI_RBF_SIZE_OFFSET,0x0);
if (!time_remain) {
mspi_infomsg("timeout\n");
return FALSE;
}
return TRUE;
}
//-------------------------------------------------------------------------------------------------
/// Description : read data from MSPI
/// @param pData \b IN :pointer to receive data from MSPI read buffer
/// @param u16Size \ b OTU : read data size
/// @return TRUE : read data success
/// @return FALSE : read data fail
//-------------------------------------------------------------------------------------------------
BOOL HAL_MSPI_Read(struct mstar_spi *bs, MSPI_CH eChannel, U8 *pData, U16 u16Size)
{
U8 u8Index = 0;
U16 u16TempBuf = 0;
U16 i =0, j = 0;
U8 shift;
U8 isMsbBitMode = (bs->bits_per_word % 8) && !(bs->spi_mode & SPI_LSB_FIRST);
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
for(i = 0; i < u16Size; i+= MAX_READ_BUF_SIZE) {
u16TempBuf = u16Size - i;
if(u16TempBuf > MAX_READ_BUF_SIZE) {
j = MAX_READ_BUF_SIZE;
} else {
j = u16TempBuf;
}
_HAL_MSPI_RWBUFSize(bs,MSPI_READ_INDEX, j);
_HAL_MSPI_Trigger(bs);
for(u8Index = 0; u8Index < j; u8Index++) {
if(u8Index & 1) {
u16TempBuf = MSPI_READ((MSPI_READ_BUF_OFFSET + (u8Index >> 1)));
//DEBUG_MSPI(E_MSPI_DBGLV_DEBUG,printk("read Buf data %x index %d\n",u16TempBuf, u8Index));
if (isMsbBitMode)
{
if (bs->bits_per_word < 8)
{
shift = 8 - bs->bits_per_word;
pData[u8Index] = u16TempBuf >> (8 + shift);
pData[u8Index-1] = (u16TempBuf & 0xFF) >> shift;
}
else //bits_per_word=9~15
{
shift = 16 - bs->bits_per_word;
pData[u8Index] = u16TempBuf >> 8;
pData[u8Index-1] = (u16TempBuf & 0xFF) >> shift;
}
}
else {
pData[u8Index] = u16TempBuf >> 8;
pData[u8Index-1] = u16TempBuf & 0xFF;
}
} else if(u8Index == (j -1)) {
u16TempBuf = MSPI_READ((MSPI_READ_BUF_OFFSET + (u8Index >> 1)));
//DEBUG_MSPI(E_MSPI_DBGLV_DEBUG,printk("read Buf data %x index %d\n",u16TempBuf, u8Index));
if (isMsbBitMode) {
pData[u8Index] = (u16TempBuf & 0xFF) >> (8 - bs->bits_per_word);
}
else {
pData[u8Index] = u16TempBuf & 0xFF;
}
}
//printk("******************* read Buf data %x index %d\n",u16TempBuf, u8Index);
}
pData+= j;
}
mutex_unlock(&hal_mspi_lock);
return TRUE;
}
//------------------------------------------------------------------------------
/// Description : read data from MSPI
/// @param pData \b OUT :pointer to write data to MSPI write buffer
/// @param u16Size \ b OTU : write data size
/// @return TRUE : write data success
/// @return FALSE : wirte data fail
//------------------------------------------------------------------------------
inline static U16 _bit_mode_write_pack_bits(U8 bits_per_word, U8 data0, U8 data1)
{
U8 shift;
U16 u16TempBuf;
if (bits_per_word < 8)
{
shift = 8 - bits_per_word;
u16TempBuf = (data1 << (8+shift)) | (data0 << shift);
}
else //bits_per_word=9~15
{
shift = 16 - bits_per_word;
u16TempBuf = (data1 << 8) | (data0 << shift);
}
return u16TempBuf;
}
BOOL HAL_MSPI_Write(struct mstar_spi *bs, MSPI_CH eChannel, U8 *pData, U16 u16Size)
{
U8 u8Index = 0, u8TempBuf;
U16 u16TempBuf = 0;
U8 shift;
U8 isMsbBitMode = (bs->bits_per_word % 8) && !(bs->spi_mode & SPI_LSB_FIRST);
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
for(u8Index = 0; u8Index < u16Size; u8Index++) {
if(u8Index & 1) {
if (isMsbBitMode) {
if (bs->bits_per_word < 8)
{
shift = 8 - bs->bits_per_word;
u16TempBuf = (pData[u8Index] << (8+shift)) | (pData[u8Index-1] << shift);
}
else //bits_per_word=9~15
{
shift = 16 - bs->bits_per_word;
u16TempBuf = (pData[u8Index] << 8) | (pData[u8Index-1] << shift);
}
}
else {
u16TempBuf = (pData[u8Index] << 8) | pData[u8Index-1];
}
mspi_infomsg("write Buf data %x index %d\n",u16TempBuf, u8Index);
MSPI_WRITE((MSPI_WRITE_BUF_OFFSET + (u8Index >> 1)),u16TempBuf);
} else if(u8Index == (u16Size -1)) {
if (isMsbBitMode) {
u8TempBuf = pData[u8Index] << (8 - bs->bits_per_word);
}
else {
u8TempBuf = pData[u8Index];
}
mspi_infomsg("write Buf data %x index %d\n",u8TempBuf, u8Index);
MSPI_WRITE((MSPI_WRITE_BUF_OFFSET + (u8Index >> 1)),u8TempBuf);
}
}
_HAL_MSPI_RWBUFSize(bs,MSPI_WRITE_INDEX, u16Size);
_HAL_MSPI_Trigger(bs);
// set write data size
mutex_unlock(&hal_mspi_lock);
return TRUE;
}
//------------------------------------------------------------------------------
/// Description : Reset CLK register setting of MSPI
/// @param NONE
/// @return TRUE : reset complete
//------------------------------------------------------------------------------
BOOL HAL_MSPI_Reset_CLKConfig(struct mstar_spi *bs,MSPI_CH eChannel)
{
U16 Tempbuf;
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
//reset clock
Tempbuf = MSPI_READ(MSPI_CTRL_OFFSET);
Tempbuf &= 0x3F;
MSPI_WRITE(MSPI_CTRL_OFFSET, Tempbuf);
mutex_unlock(&hal_mspi_lock);
return TRUE;
}
U8 HAL_MSPI_DCConfigMax(eDC_config eDCField)
{
switch(eDCField)
{
case E_MSPI_TRSTART:
return MSPI_DC_TRSTART_MAX;
case E_MSPI_TREND:
return MSPI_DC_TREND_MAX;
case E_MSPI_TB:
return MSPI_DC_TB_MAX;
case E_MSPI_TRW:
return MSPI_DC_TRW_MAX;
default:
return 0;
}
}
//------------------------------------------------------------------------------
/// Description : Set TrStart timing of DC config
/// @return E_MSPI_OK :
/// @return >1 : failed to set TrStart timing
//------------------------------------------------------------------------------
static U8 _MDrv_DC_TrStartSetting(struct mstar_spi *bs,U8 u8Channel,U8 TrStart)
{
U8 u8TrStartMax;
U8 errnum = E_MSPI_OK;
u8TrStartMax = HAL_MSPI_DCConfigMax(E_MSPI_TRSTART);
if(TrStart > u8TrStartMax)
errnum = E_MSPI_PARAM_OVERFLOW;
else
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TRSTART ,TrStart);
return errnum;
}
//------------------------------------------------------------------------------
/// Description : Reset DC register setting of MSPI
/// @param NONE
/// @return TRUE : reset complete
//------------------------------------------------------------------------------
BOOL HAL_MSPI_Reset_DCConfig(struct mstar_spi *bs,MSPI_CH eChannel)
{
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
//DC reset
MSPI_WRITE(MSPI_DC_TR_START_OFFSET, 0x00);
MSPI_WRITE(MSPI_DC_TB_OFFSET, 0x00);
mutex_unlock(&hal_mspi_lock);
return TRUE;
}
//------------------------------------------------------------------------------
/// Description : SPI chip select enable and disable
/// @param Enable \b OUT: enable or disable chip select
//------------------------------------------------------------------------------
static void _HAL_MSPI_ChipSelect(struct mstar_spi *bs,BOOL Enable ,U8 eSelect)
{
U16 regdata = 0;
U8 bitmask = 0;
regdata = MSPI_READ(MSPI_CHIP_SELECT_OFFSET);
if(Enable) {
bitmask = ~(1 << eSelect);
regdata &= bitmask;
} else {
bitmask = (1 << eSelect);
regdata |= bitmask;
}
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, regdata);
}
//------------------------------------------------------------------------------
/// Description : Set MSPI chip select
/// @param u8CS \u8 OUT: MSPI chip select
/// @return void:
//------------------------------------------------------------------------------
void HAL_MSPI_SetChipSelect(struct mstar_spi *bs,MSPI_CH eChannel, BOOL Enable, U8 u8CS)
{
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
_HAL_MSPI_ChipSelect(bs, Enable, u8CS);
mutex_unlock(&hal_mspi_lock);
}
// add to sync code from utopia for localdimming to set clk
void MDrv_MSPI_ChipSelect(struct mstar_spi *bs,U8 u8Channel, BOOL Enable, U8 u8CS)
{
HAL_MSPI_SetChipSelect(bs,(MSPI_CH)u8Channel,Enable,u8CS);
return;
}
//-------------------------------------------------------------------------------------------------
/// Description : read data from MSPI
/// @param pData \b IN :pointer to receive data from MSPI read buffer
/// @param u16Size \ b OTU : read data size
/// @return the errorno of operation
//-------------------------------------------------------------------------------------------------
U8 MDrv_MSPI_Read(struct mstar_spi *bs, U8 u8Channel, U8 *pData, U16 u16Size)
{
//MSPI_ErrorNo errorno = E_MSPI_OK;
U8 u8Index = 0;
U8 u8TempFrameCnt=0;
U8 U8TempLastFrameCnt=0;
int ret = 0;
if(pData == NULL) {
return E_MSPI_NULL;
}
u8TempFrameCnt = u16Size/MAX_WRITE_BUF_SIZE; //Cut data to frame by max frame size
U8TempLastFrameCnt = u16Size%MAX_WRITE_BUF_SIZE; //Last data less than a MAX_WRITE_BUF_SIZE fame
for (u8Index = 0; u8Index < u8TempFrameCnt; u8Index++) {
ret = HAL_MSPI_Read(bs,(MSPI_CH)u8Channel,pData+u8Index*MAX_WRITE_BUF_SIZE,MAX_WRITE_BUF_SIZE);
if (!ret) {
return E_MSPI_OPERATION_ERROR;
}
}
if(U8TempLastFrameCnt) {
ret = HAL_MSPI_Read(bs,(MSPI_CH)u8Channel,pData+u8TempFrameCnt*MAX_WRITE_BUF_SIZE,U8TempLastFrameCnt);
}
if (!ret) {
return E_MSPI_OPERATION_ERROR;
}
return E_MSPI_OK;
}
//------------------------------------------------------------------------------
/// Description : write data from MSPI
/// @param pData \b OUT :pointer to write data to MSPI write buffer
/// @param u16Size \ b OTU : write data size
/// @return the errorno of operation
//------------------------------------------------------------------------------
U8 MDrv_MSPI_Write(struct mstar_spi *bs,U8 u8Channel, U8 *pData, U16 u16Size)
{
U8 u8Index = 0;
U8 u8TempFrameCnt=0;
U8 U8TempLastFrameCnt=0;
BOOL ret = false;
u8TempFrameCnt = u16Size/MAX_WRITE_BUF_SIZE; //Cut data to frame by max frame size
U8TempLastFrameCnt = u16Size%MAX_WRITE_BUF_SIZE; //Last data less than a MAX_WRITE_BUF_SIZE fame
for (u8Index = 0; u8Index < u8TempFrameCnt; u8Index++)
{
ret = HAL_MSPI_Write(bs, (MSPI_CH)u8Channel,pData+u8Index*MAX_WRITE_BUF_SIZE,MAX_WRITE_BUF_SIZE);
if (!ret) {
return E_MSPI_OPERATION_ERROR;
}
}
if(U8TempLastFrameCnt)
{
ret = HAL_MSPI_Write(bs, (MSPI_CH)u8Channel,pData+u8TempFrameCnt*MAX_WRITE_BUF_SIZE,U8TempLastFrameCnt);
}
if (!ret) {
return E_MSPI_OPERATION_ERROR;
}
return E_MSPI_OK;
}
U8 MDrv_MSPI_DMA_Read(struct mstar_spi *bs, U8 u8Channel, U8 *pData, U16 u16Size)
{
U32 data_addr = (U32)pData;
if(pData == NULL) {
return E_MSPI_NULL;
}
mutex_lock(&hal_mspi_lock);
HAL_MSPI_SelectCLK(bs, u8Channel);
MOVDMA_WRITE( DMA_RW, DMA_READ); // 1 for dma read from device
MSPI_WRITE(MSPI_DMA_ENABLE, 0x01);
MSPI_WRITE(MSPI_DMA_RW_MODE, MSPI_DMA_READ);
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_L, u16Size & 0xFFFF );
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_H, (u16Size>>16)& 0x00FF); // 24bit
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_L, u16Size & 0xFFFF );
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_H, u16Size>>16 );
//invalidate_dcache_range(data_addr, ((data_addr + u16Size) & ~(0x00000040 - 1)));
data_addr -= SPI_MIU0_BUS_BASE;
MOVDMA_WRITE(MOV_DMA_DST_ADDR_L, data_addr & 0x0000FFFF );
MOVDMA_WRITE(MOV_DMA_DST_ADDR_H, data_addr >>16 );
MOVDMA_WRITE(0x00,0x01);//dma enable
_HAL_MSPI_ChipSelect(bs,1,0);//enable chip select for device0 (pulled low)
_HAL_MSPI_RWBUFSize(bs,MSPI_READ_INDEX, 0); //spi length = 0
_HAL_MSPI_Trigger(bs);
MOVDMA_WRITE(0x00,0x0);//dma disable
MSPI_WRITE(MSPI_DMA_ENABLE, 0x0);
_HAL_MSPI_ChipSelect(bs,0,0);//disable chip select for device0 (pulled low)
mutex_unlock(&hal_mspi_lock);
return E_MSPI_OK;
}
U8 MDrv_MSPI_DMA_Write(struct mstar_spi *bs,U8 u8Channel, U8 *pData, U16 u16Size)
{
U32 data_addr = (U32)pData;
mutex_lock(&hal_mspi_lock);
mspi_infomsg("### MDrv_MSPI_DMA_Write\r\n");
HAL_MSPI_SelectCLK(bs, u8Channel);
MOVDMA_WRITE( DMA_RW, DMA_WRITE );//0 for dma write to device
MOVDMA_WRITE( DMA_DEVICE_MODE, 0x0001 ); // 1 to enable dma device mode
MOVDMA_WRITE( DMA_DEVICE_SEL, bs->u8channel); //0 select mspi0 , 1 select mspi1
MSPI_WRITE(MSPI_DMA_ENABLE, 0x01);
MSPI_WRITE(MSPI_DMA_RW_MODE, MSPI_DMA_WRITE);
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_L, u16Size & 0xFFFF );
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_H, u16Size>>16 );
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_L, u16Size & 0xFFFF );
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_H, u16Size>>16 );
flush_cache(data_addr, u16Size);
data_addr -= SPI_MIU0_BUS_BASE;
MOVDMA_WRITE(MOV_DMA_SRC_ADDR_L, data_addr & 0x0000FFFF );
MOVDMA_WRITE(MOV_DMA_SRC_ADDR_H, data_addr >>16);
MOVDMA_WRITE(0x00,0x01);//dma enable
_HAL_MSPI_ChipSelect(bs,1,0);//enable chip select for device0 (pulled low)
_HAL_MSPI_RWBUFSize(bs,MSPI_WRITE_INDEX, 0);
_HAL_MSPI_Trigger(bs);
MOVDMA_WRITE(0x00,0x0);//dma disable
MSPI_WRITE(MSPI_DMA_ENABLE, 0x0);
_HAL_MSPI_ChipSelect(bs,0,0);//disable chip select for device0 (pulled low)
mutex_unlock(&hal_mspi_lock);
return E_MSPI_OK;
}
u8 MDrv_MSPI_Init(struct mstar_spi *bs,u8 u8Channel,u8 u8Mode)
{
u8 errorno = E_MSPI_OK;
HAL_MSPI_Init(bs,(MSPI_CH)u8Channel,u8Mode);
HAL_MSPI_IntEnable(bs,(MSPI_CH)u8Channel,true);
gbInitFlag = true;
return errorno;
}
//------------------------------------------------------------------------------
/// Description : Set TrEnd timing of DC config
/// @return E_MSPI_OK :
/// @return >1 : failed to set TrEnd timing
//------------------------------------------------------------------------------
static U8 _MDrv_DC_TrEndSetting(struct mstar_spi *bs,U8 u8Channel,U8 TrEnd)
{
U8 u8TrEndMax;
U8 errnum = E_MSPI_OK;
u8TrEndMax = HAL_MSPI_DCConfigMax(E_MSPI_TREND);
if(TrEnd > u8TrEndMax)
errnum = E_MSPI_PARAM_OVERFLOW;
else
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TREND ,TrEnd);
return errnum;
}
//------------------------------------------------------------------------------
/// Description : Set TB timing of DC config
/// @return E_MSPI_OK :
/// @return >1 : failed to set TB timing
//------------------------------------------------------------------------------
static U8 _MDrv_DC_TBSetting(struct mstar_spi *bs,U8 u8Channel,U8 TB)
{
U8 u8TBMax;
U8 errnum = E_MSPI_OK;
u8TBMax = HAL_MSPI_DCConfigMax(E_MSPI_TB);
if(TB > u8TBMax)
errnum = E_MSPI_PARAM_OVERFLOW;
else
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TB ,TB);
return errnum;
}
//------------------------------------------------------------------------------
/// Description : Set TRW timing of DC config
/// @return E_MSPI_OK :
/// @return >1 : failed to set TRW timging
//------------------------------------------------------------------------------
static U8 _MDrv_DC_TRWSetting(struct mstar_spi *bs,U8 u8Channel,U8 TRW)
{
U8 u8TRWMax;
U8 errnum = E_MSPI_OK;
u8TRWMax = HAL_MSPI_DCConfigMax(E_MSPI_TRW);
if(TRW > u8TRWMax)
errnum = E_MSPI_PARAM_OVERFLOW;
else
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TRW ,TRW);
return errnum;
}
//------------------------------------------------------------------------------
/// Description : config spi transfer timing
/// @param ptDCConfig \b OUT struct pointer of transfer timing config
/// @return E_MSPI_OK : succeed
/// @return E_MSPI_DCCONFIG_ERROR : failed to config transfer timing
//------------------------------------------------------------------------------
U8 MDrv_MSPI_DCConfig(struct mstar_spi *bs,U8 u8Channel, MSPI_DCConfig *ptDCConfig)
{
U8 errnum = E_MSPI_OK;
//check init
if(!gbInitFlag)
return E_MSPI_INIT_FLOW_ERROR;
if(ptDCConfig == NULL)
{
HAL_MSPI_Reset_DCConfig(bs,(MSPI_CH)u8Channel);
return E_MSPI_OK;
}
errnum = _MDrv_DC_TrStartSetting(bs,u8Channel,ptDCConfig->u8TrStart);
if(errnum != E_MSPI_OK)
goto ERROR_HANDLE;
errnum = _MDrv_DC_TrEndSetting(bs,u8Channel,ptDCConfig->u8TrEnd);
if(errnum != E_MSPI_OK)
goto ERROR_HANDLE;
errnum = _MDrv_DC_TBSetting(bs,u8Channel,ptDCConfig->u8TB);
if(errnum != E_MSPI_OK)
goto ERROR_HANDLE;
errnum = _MDrv_DC_TRWSetting(bs,u8Channel,ptDCConfig->u8TRW);
if(errnum != E_MSPI_OK)
goto ERROR_HANDLE;
return E_MSPI_OK;
ERROR_HANDLE:
errnum |= E_MSPI_DCCONFIG_ERROR;
return errnum;
}
void HAL_MSPI_SetCLKTiming(struct mstar_spi *bs,MSPI_CH eChannel, eCLK_config eCLKField, U8 u8CLKVal)
{
U16 u16TempBuf = 0;
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
switch(eCLKField) {
case E_MSPI_POL:
u16TempBuf = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
u16TempBuf &= ~(MSPI_CLK_POLARITY_MASK);
u16TempBuf |= u8CLKVal << MSPI_CLK_POLARITY_BIT_OFFSET;
break;
case E_MSPI_PHA:
u16TempBuf = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
u16TempBuf &= ~(MSPI_CLK_PHASE_MASK);
u16TempBuf |= u8CLKVal << MSPI_CLK_PHASE_BIT_OFFSET;
break;
case E_MSPI_CLK:
u16TempBuf = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
u16TempBuf &= MSPI_CLK_CLOCK_MASK;
u16TempBuf |= u8CLKVal << MSPI_CLK_CLOCK_BIT_OFFSET;
break;
}
MSPI_WRITE(MSPI_CLK_CLOCK_OFFSET, u16TempBuf);
mutex_unlock(&hal_mspi_lock);
}
void HAL_MSPI_SetLSB(struct mstar_spi *bs,MSPI_CH eChannel, BOOL enable)
{
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
MSPI_WRITE(MSPI_LSB_FIRST_OFFSET, enable);
mutex_unlock(&hal_mspi_lock);
}
#define NUM_SPI_CKG 4
#define NUM_SPI_CLKDIV 8
#define NUM_SPI_CLKRATES 32 //NUM_SPI_CKG * NUM_SPI_CLKDIVRATE
static U8 clk_spi_ckg[NUM_SPI_CKG] = {108, 54, 12, 144};
static U16 clk_spi_div[NUM_SPI_CLKDIV] = {2, 4, 8, 16, 32, 64, 128, 256};
static ST_DRV_MSPI_CLK clk_buffer[NUM_SPI_CLKRATES];
U32 HAL_MSPI_CLK_Config(struct mstar_spi *bs,U8 u8Chanel,U32 u32MspiClk)
{
U8 i = 0;
U8 j= 0;
U16 TempData = 0;
U32 clk =0;
ST_DRV_MSPI_CLK temp;
if(u8Chanel >=2)
return FALSE;
memset(&temp,0,sizeof(ST_DRV_MSPI_CLK));
memset(&clk_buffer,0,sizeof(ST_DRV_MSPI_CLK)*NUM_SPI_CLKRATES);
for(i = 0;i < NUM_SPI_CKG;i++)//clk_spi_m_p1
{
for(j = 0;j<NUM_SPI_CLKDIV;j++)//spi div
{
clk = clk_spi_ckg[i]*1000000;
clk_buffer[j+8*i].u8ClkSpi_cfg = i;
clk_buffer[j+8*i].u8ClkSpi_DIV = j ;
clk_buffer[j+8*i].u32ClkSpi = clk/clk_spi_div[j];
}
}
for(i = 0;i<NUM_SPI_CLKRATES;i++)
{
for(j = i;j<NUM_SPI_CLKRATES;j++)
{
if(clk_buffer[i].u32ClkSpi > clk_buffer[j].u32ClkSpi)
{
memcpy(&temp,&clk_buffer[i],sizeof(ST_DRV_MSPI_CLK));
memcpy(&clk_buffer[i],&clk_buffer[j],sizeof(ST_DRV_MSPI_CLK));
memcpy(&clk_buffer[j],&temp,sizeof(ST_DRV_MSPI_CLK));
}
}
}
for(i = 0;i<NUM_SPI_CLKRATES;i++)
{
if(u32MspiClk <= clk_buffer[i].u32ClkSpi)
{
break;
}
}
if (NUM_SPI_CLKRATES == i)
{
i--;
}
//match Closer clk
else if ((i) && ((u32MspiClk - clk_buffer[i-1].u32ClkSpi)<(clk_buffer[i].u32ClkSpi - u32MspiClk)))
{
i -= 1;
}
mspi_dbgmsg("[Lwc Debug] u8ClkSpi_P1 =%d\n",clk_buffer[i].u8ClkSpi_cfg);
mspi_dbgmsg("[Lwc Debug] u8ClkSpi_DIV =%d\n",clk_buffer[i].u8ClkSpi_DIV);
mspi_dbgmsg("[Lwc Debug] u32ClkSpi = %d\n",clk_buffer[i].u32ClkSpi);
if(u8Chanel == E_MSPI0)//mspi0
{
// CLK SETTING
TempData = CLK_READ(MSPI0_CLK_CFG);
TempData &= ~(MSPI0_CLK_MASK);
TempData |= (clk_buffer[i].u8ClkSpi_cfg<<2);
CLK_WRITE(MSPI0_CLK_CFG, TempData);
}
TempData = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
TempData &= MSPI_CLK_CLOCK_MASK;
TempData |= clk_buffer[i].u8ClkSpi_DIV << MSPI_CLK_CLOCK_BIT_OFFSET;
MSPI_WRITE(MSPI_CLK_CLOCK_OFFSET, TempData);
return clk_buffer[i].u32ClkSpi;
}
//------------------------------------------------------------------------------
/// Description : config spi clock setting
/// @param ptCLKConfig \b OUT struct pointer of clock config
/// @return E_MSPI_OK : succeed
/// @return E_MSPI_CLKCONFIG_ERROR : failed to config spi clock
//------------------------------------------------------------------------------
U8 MDrv_MSPI_SetMode(struct mstar_spi *bs,U8 u8Channel, MSPI_Mode_Config_e eMode)
{
if (eMode >= E_MSPI_MODE_MAX) {
return E_MSPI_PARAM_OVERFLOW;
}
switch (eMode) {
case E_MSPI_MODE0:
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,false);
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,false);
break;
case E_MSPI_MODE1:
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,false);
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,true);
break;
case E_MSPI_MODE2:
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,true);
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,false);
break;
case E_MSPI_MODE3:
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,true);
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,true);
break;
default:
HAL_MSPI_Reset_CLKConfig(bs,(MSPI_CH)u8Channel);
return E_MSPI_OPERATION_ERROR;
}
return E_MSPI_OK;
}
void HAL_MSPI_SetPerFrameSize(struct mstar_spi *bs,MSPI_CH eChannel, BOOL bDirect, U8 u8BufOffset, U8 u8PerFrameSize)
{
U8 u8Index = 0;
U16 u16TempBuf = 0;
U8 u8BitOffset = 0;
U16 u16regIndex = 0;
mutex_lock(&hal_mspi_lock);
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
if(bDirect == MSPI_READ_INDEX) {
u16regIndex = MSPI_FRAME_RBIT_OFFSET;
} else {
u16regIndex = MSPI_FRAME_WBIT_OFFSET;
}
if(u8BufOffset >=4) {
u8Index++;
u8BufOffset -= 4;
}
u8BitOffset = u8BufOffset * MSPI_FRAME_BIT_FIELD;
u16TempBuf = MSPI_READ(u16regIndex+ u8Index);
u16TempBuf &= ~(MSPI_FRAME_BIT_MASK << u8BitOffset);
u16TempBuf |= u8PerFrameSize << u8BitOffset;
//printf("%s: %x %x\n",__func__, u16regIndex + u8Index, u16TempBuf);
MSPI_WRITE((u16regIndex + u8Index), u16TempBuf);
mutex_unlock(&hal_mspi_lock);
}
//------------------------------------------------------------------------------
/// Description : config spi transfer timing
/// @param ptDCConfig \b OUT struct pointer of bits of buffer tranferred to slave config
/// @return E_MSPI_OK : succeed
/// @return E_MSPI_FRAMECONFIG_ERROR : failed to config transfered bit per buffer
//------------------------------------------------------------------------------
U8 MDrv_MSPI_FRAMEConfig(struct mstar_spi *bs,U8 u8Channel, MSPI_FrameConfig *ptFrameConfig)
{
U8 errnum = E_MSPI_OK;
U8 u8Index = 0;
if(ptFrameConfig == NULL) {
HAL_MSPI_Reset_FrameConfig(bs,(MSPI_CH)u8Channel);
return E_MSPI_OK;
}
// read buffer bit config
for(u8Index = 0; u8Index < MAX_READ_BUF_SIZE; u8Index++) {
if(ptFrameConfig->u8RBitConfig[u8Index] > MSPI_FRAME_BIT_MAX) {
errnum = E_MSPI_PARAM_OVERFLOW;
} else {
HAL_MSPI_SetPerFrameSize(bs,(MSPI_CH)u8Channel, MSPI_READ_INDEX, u8Index, ptFrameConfig->u8RBitConfig[u8Index]);
}
}
//write buffer bit config
for(u8Index = 0; u8Index < MAX_WRITE_BUF_SIZE; u8Index++) {
if(ptFrameConfig->u8WBitConfig[u8Index] > MSPI_FRAME_BIT_MAX) {
errnum = E_MSPI_PARAM_OVERFLOW;
} else {
//printf("set Wbuf[%d] %d\n", u8Index, ptFrameConfig->u8WBitConfig[u8Index]);
HAL_MSPI_SetPerFrameSize(bs,(MSPI_CH)u8Channel, MSPI_WRITE_INDEX, u8Index, ptFrameConfig->u8WBitConfig[u8Index]);
}
}
return errnum;
}
// add to sync code from utopia for localdimming to set clk
U32 MDrv_MSPI_SetCLK(struct mstar_spi *bs,U8 u8Channel, U32 u32MspiClk)
{
int u32SpiClk;
u32SpiClk = HAL_MSPI_CLK_Config(bs,(MSPI_CH)u8Channel,u32MspiClk);
return u32SpiClk;
}
void mspi_config(struct mstar_spi *bs,u8 u8Channel)
{
MSPI_DCConfig stDCConfig;
MSPI_FrameConfig stFrameConfig;
MSPI_Mode_Config_e mspimode = E_MSPI_MODE0;
stDCConfig.u8TB = 0;
stDCConfig.u8TrEnd = 0x0;
stDCConfig.u8TrStart = 0x0;
stDCConfig.u8TRW = 0;
memset(&stFrameConfig,0x07,sizeof(MSPI_FrameConfig));
MDrv_MSPI_Init(bs,u8Channel,bs->u32pad_mode);
MDrv_MSPI_DCConfig(bs,u8Channel, &stDCConfig);
MDrv_MSPI_SetMode(bs,u8Channel, mspimode);
MDrv_MSPI_FRAMEConfig(bs,u8Channel,&stFrameConfig);
MDrv_MSPI_SetCLK(bs,u8Channel,54000000); //200000 CLK
MDrv_MSPI_ChipSelect(bs,u8Channel,0,0);
HAL_MSPI_SetLSB(bs,u8Channel, 0);
return;
}
static int mstar_spi_start_transfer(struct spi_device *spi,
struct spi_transfer *tfr)
{
struct mstar_spi *bs = to_ss_spi_slave(spi);
bs->tx_buf = tfr->tx_buf;
bs->rx_buf = tfr->rx_buf;
bs->len = tfr->len;
MDrv_MSPI_ChipSelect(bs,_hal_msp.eCurrentCH,1,0); // mark for testing not control cs
/*if(tfr->speed_hz != NULL){
MDrv_MSPI_SetCLK(_hal_msp.eCurrentCH,tfr->speed_hz);
}*/
if(bs->tx_buf != NULL){
mspi_infomsg("bs->tx_buf=%x,%x... len=%d byte(s) dma=%d\n",bs->tx_buf[0],bs->tx_buf[1],tfr->len,bs->xfer_w_dma);
if(bs->xfer_w_dma)
MDrv_MSPI_DMA_Write(bs, _hal_msp.eCurrentCH,(U8 *)bs->tx_buf,(U16)bs->len);
else
MDrv_MSPI_Write(bs, _hal_msp.eCurrentCH,(U8 *)bs->tx_buf,(U16)bs->len);
}
if(bs->rx_buf != NULL){
if(bs->xfer_w_dma)
MDrv_MSPI_DMA_Read(bs,_hal_msp.eCurrentCH,(U8 *)bs->rx_buf,(U16)bs->len);
else
MDrv_MSPI_Read(bs,_hal_msp.eCurrentCH,(U8 *)bs->rx_buf,(U16)bs->len);
mspi_dbgmsg("bs->rx_buf=%x,%x\n",bs->rx_buf[0],bs->rx_buf[1]);
}
//printk("bs->len=%d\n",bs->len);
return 0;
}
static int mstar_spi_finish_transfer(struct spi_device *spi,
struct spi_transfer *tfr, bool cs_change)
{
struct mstar_spi *bs = to_ss_spi_slave(spi);
//printk("[mstar_spi_finish_transfer] cs_change=%d\n",cs_change);
#if 1
if (cs_change){
/* Clear TA flag */
MDrv_MSPI_ChipSelect(bs,_hal_msp.eCurrentCH,0,0);
//MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, 0xFFFF);
}
#endif
return 0;
}
static int mstar_spi_setup(struct mstar_spi *bs, unsigned int mode, unsigned int max_speed_hz)
{
MDrv_MSPI_SetMode(bs,bs->u8channel, mode & (SPI_CPHA | SPI_CPOL));
HAL_MSPI_SetLSB(bs,bs->u8channel,(mode & SPI_LSB_FIRST)>>3);
MDrv_MSPI_SetCLK(bs,bs->u8channel,max_speed_hz);
mspi_dbgmsg("<~~~~~~~~~~~~~~~~>SETUP :mode:%x,speed:%d channel:%d\n",mode,max_speed_hz,bs->u8channel);
return 0;
}
static int mstar_spi_transfer_one(struct spi_slave *spi,
struct spi_transfer *tfr)
{
int err = 0;
bool cs_change = 1;
{
err = mstar_spi_start_transfer(spi, tfr);
if (err){
mspi_errmsg("start_transfer err\n");
goto out;
}
err = mstar_spi_finish_transfer(spi, tfr, cs_change);
if (err){
mspi_errmsg("finish transfer err\n");
goto out;
}
}
out:
return 0;
}
//------------------------------------------------------
// uboot spi API and help functions
//-------------------------------------------------------
static void mstar_spi_turn_on(struct mstar_spi *bs, unsigned int bus)
{
if (bus == 0)
{
CLK_WRITE_MASK(MSPI0_CLK_CFG, 0, MSPI0_CLKGATE_MASK);
}
}
static void mstar_spi_turn_off(struct mstar_spi *bs, unsigned int bus)
{
if (bus == 0)
{
CLK_WRITE_MASK(MSPI0_CLK_CFG, 1, MSPI0_CLKGATE_MASK);
}
}
static int mstar_spi_set_framecfg(struct mstar_spi *bs, int bits_per_word)
{
MSPI_FrameConfig stFrameConfig;
int i;
if (bits_per_word > 16)
return -1;
else if (bits_per_word > 8)
{
for (i = 0; i < MAX_WRITE_BUF_SIZE; i+=2)
{
stFrameConfig.u8WBitConfig[i] = bits_per_word - 8 -1;
stFrameConfig.u8WBitConfig[i+1] = 8 -1;
}
for (i = 0; i < MAX_READ_BUF_SIZE; i+=2)
{
stFrameConfig.u8RBitConfig[i] = bits_per_word - 8 -1;
stFrameConfig.u8RBitConfig[i+1] = 8 -1;
}
}
else
{
for (i = 0; i < MAX_WRITE_BUF_SIZE; i++)
{
stFrameConfig.u8WBitConfig[i] = bits_per_word -1;
}
for (i = 0; i < MAX_READ_BUF_SIZE; i++)
{
stFrameConfig.u8WBitConfig[i] = bits_per_word -1;
}
}
MDrv_MSPI_FRAMEConfig(bs,bs->u8channel,&stFrameConfig);
return 0;
}
void spi_init(void)
{
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct mstar_spi *bs;
u16 bad_bits;
//if (!spi_cs_is_valid(bus, cs))
// return NULL;
bs = spi_alloc_slave(struct mstar_spi, bus, cs);
if (!bs)
return NULL;
if (bus != 0) // I2m supports MSPI0 only
return NULL;
bad_bits = mode & ~MSTAR_SPI_MODE_BITS;
if (bad_bits) {
mspi_errmsg("spi setup: unsupported mode bits %x\n",bad_bits);
return NULL;
}
bs->VirtMspBaseAddr = (char*)(MS_BASE_REG_RIU_PA + BASE_REG_MSPI0_ADDR);
bs->VirtClkBaseAddr = (char*)(MS_BASE_REG_RIU_PA + BASE_REG_CLK_ADDR);
bs->VirtChiptopBaseAddr = (char*)(MS_BASE_REG_RIU_PA + BASE_REG_CHIPTOP_ADDR);
bs->VirtMovdmaBaseAddr = (char*)(MS_BASE_REG_RIU_PA + BASE_REG_MOVDMA_ADDR);
bs->u8channel = E_MSPI0;
bs->u32pad_mode = MSPI0_PADMUX_MODE; //padmux mode
bs->spi_mode = mode;
bs->max_speed_hz = max_hz;
bs->support_dma = SUPPORT_DMA;
bs->xfer_w_dma = bs->support_dma;
mspi_dbgmsg("%s: addr: mspi=0x%x clk=0x%x chiptop=0x%x\n",__func__,
(u32)bs->VirtMspBaseAddr, (u32)bs->VirtClkBaseAddr, (u32)bs->VirtChiptopBaseAddr);
/* initialise the hardware */
mspi_config(bs,0);
return &bs->slave;
}
void spi_free_slave(struct spi_slave *slave)
{
struct mstar_spi *bs = to_ss_spi_slave(slave);
free(bs);
}
void spi_select_pad(struct spi_slave *slave, int gpio_padode)
{
struct mstar_spi *bs = to_ss_spi_slave(slave);
if (gpio_padode < PINMUX_FOR_SPI0_MODE_1 || gpio_padode > PINMUX_FOR_SPI0_MODE_6)
return;
bs->u32pad_mode = gpio_padode - PINMUX_FOR_SPI0_MODE_1 + 1;
MDrv_GPIO_PadGroupMode_Set(gpio_padode);
}
int spi_claim_bus(struct spi_slave *slave)
{
struct mstar_spi *bs = to_ss_spi_slave(slave);
mspi_dbgmsg("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
mstar_spi_turn_on(bs, slave->bus);
mstar_spi_setup(bs, bs->spi_mode, bs->max_speed_hz);
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
struct mstar_spi *bs = to_ss_spi_slave(slave);
mspi_dbgmsg("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
mstar_spi_turn_off(bs, slave->bus);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
struct spi_transfer tfr;
struct mstar_spi *bs = to_ss_spi_slave(slave);
// setup transfer bit mask
bs->xfer_w_dma = (bitlen % 8 ==0) ? bs->support_dma : false;
if (bitlen % 8)
{
if (bitlen > 16)
{
mspi_errmsg("%s: only support bit mode up to 16 bits\n", __func__);
return -1;
}
bs->bits_per_word = bitlen;
mstar_spi_set_framecfg(bs, bs->bits_per_word);
}
tfr.tx_buf = dout;
tfr.rx_buf = din;
tfr.len = DIV_ROUND_UP(bitlen, 8);
return mstar_spi_transfer_one(slave, &tfr);
}