522 lines
11 KiB
C
522 lines
11 KiB
C
|
#include <linux/spi/spi.h>
|
||
|
#include "bcm_mirror.h"
|
||
|
#include "spi_mpc.h"
|
||
|
#include "mirror_drv.h"
|
||
|
#include "spbx_log/spbx_log.h"
|
||
|
|
||
|
#define MIR_PORT_PAG (0x3)
|
||
|
#define MIR_CTL_REG (0x10)
|
||
|
#define MIR_CAP_PORT_REG (0x18)
|
||
|
|
||
|
#define EN_OUT_MIR_FLTR (1<<4)
|
||
|
#define EN_IN_MIR_FLTR (1<<5)
|
||
|
|
||
|
#define MIR_CAP_PORT(x) (1 <<(x))
|
||
|
|
||
|
#define SW_READ_MODE (0x60)
|
||
|
#define SW_WRITE_MODE (0x61)
|
||
|
|
||
|
#define SW_SPI_DATA_REG(x) (0xF0 + (x))
|
||
|
#define SW_SPI_STATUS_REG (0xFE)
|
||
|
#define SW_SPI_PAGE_REG (0xFF)
|
||
|
|
||
|
#define SW_STATUS_SPIF (1<<7)
|
||
|
#define SW_STATUS_WCOL (1<<6)
|
||
|
#define SW_STATUS_RACK (1<<5)
|
||
|
#define SW_STATUS_MDIO_ST (1<<2)
|
||
|
#define SW_STATUS_RXRDY (1<<1)
|
||
|
#define SW_STATUS_TXRDY (0<<1)
|
||
|
#define SW_MAX_TIME (10)
|
||
|
|
||
|
#define MAX_PORT (28)
|
||
|
|
||
|
static unsigned char g_page_addr = 0;
|
||
|
|
||
|
static int sw_get_spi_status(unsigned char* status)
|
||
|
{
|
||
|
char temp_rx[3];
|
||
|
char temp_tx[3];
|
||
|
struct spi_transfer t;
|
||
|
struct spi_message m;
|
||
|
struct spi_device* spi = DRV_GetDrvDetail()->pSPIDevice;
|
||
|
|
||
|
memset(temp_rx, 0, 3);
|
||
|
memset(temp_tx, 0, 3);
|
||
|
|
||
|
temp_tx[0] = SW_READ_MODE;
|
||
|
temp_tx[1] = SW_SPI_STATUS_REG;
|
||
|
temp_tx[2] = 0x0;
|
||
|
|
||
|
spi_message_init(&m);
|
||
|
|
||
|
t.tx_buf = temp_tx;
|
||
|
t.rx_buf = temp_rx;
|
||
|
t.len = 3;
|
||
|
spi_message_add_tail(&t, &m);
|
||
|
|
||
|
if(spi_sync(spi, &m) < 0)
|
||
|
{
|
||
|
printk(KERN_ERR "RD error in spi operation\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
*status = temp_rx[2];
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int sw_set_page_addr(unsigned char page)
|
||
|
{
|
||
|
struct spi_device* spi = DRV_GetDrvDetail()->pSPIDevice;
|
||
|
char temp_rx[3];
|
||
|
char temp_tx[3];
|
||
|
struct spi_transfer t;
|
||
|
struct spi_message m;
|
||
|
|
||
|
memset(temp_rx, 0, 3);
|
||
|
memset(temp_tx, 0, 3);
|
||
|
|
||
|
temp_tx[0] = SW_WRITE_MODE;
|
||
|
temp_tx[1] = SW_SPI_PAGE_REG;
|
||
|
temp_tx[2] = page;
|
||
|
|
||
|
spi_message_init(&m);
|
||
|
|
||
|
t.tx_buf = temp_tx;
|
||
|
t.rx_buf = temp_rx;
|
||
|
t.len = 3;
|
||
|
|
||
|
spi_message_add_tail(&t, &m);
|
||
|
|
||
|
if(spi_sync(spi, &m) < 0)
|
||
|
{
|
||
|
printk(KERN_ERR "RD error in spi operation\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int dummy_read(PBCM_REGS pRegs)
|
||
|
{
|
||
|
struct spi_device* spi = DRV_GetDrvDetail()->pSPIDevice;
|
||
|
unsigned char len = 3;
|
||
|
char temp_rx[3];
|
||
|
char temp_tx[3];
|
||
|
struct spi_transfer t;
|
||
|
struct spi_message m;
|
||
|
|
||
|
memset(temp_rx , 0, len);
|
||
|
memset(temp_tx , 0, len);
|
||
|
|
||
|
temp_tx[0] = SW_READ_MODE;
|
||
|
temp_tx[1] = pRegs->reg_addr;
|
||
|
temp_tx[2] = 0;
|
||
|
|
||
|
spi_message_init(&m);
|
||
|
t.tx_buf = temp_tx;
|
||
|
t.rx_buf = temp_rx;
|
||
|
t.len = 3;
|
||
|
spi_message_add_tail(&t, &m);
|
||
|
|
||
|
if(spi_sync(spi, &m) < 0)
|
||
|
{
|
||
|
printk(KERN_ERR "RD error in spi operation\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static unsigned int sw_read_reg(PBCM_REGS pRegs)
|
||
|
{
|
||
|
unsigned int index = 0;
|
||
|
unsigned char status;
|
||
|
unsigned char page_addr = pRegs->page_addr;
|
||
|
struct spi_device* spi = DRV_GetDrvDetail()->pSPIDevice;
|
||
|
|
||
|
if(spi == NULL || pRegs == NULL)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
if(sw_get_spi_status(&status))
|
||
|
{
|
||
|
status = -1;
|
||
|
index++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
while((status & SW_STATUS_SPIF) != 0 && index < SW_MAX_TIME);
|
||
|
|
||
|
|
||
|
if(index >= SW_MAX_TIME)
|
||
|
{
|
||
|
printk("status :0x%x,SPIF !=0\n", status);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if(page_addr != g_page_addr)
|
||
|
{
|
||
|
unsigned char page_addr = pRegs->page_addr;
|
||
|
|
||
|
if(!sw_set_page_addr(page_addr))
|
||
|
{
|
||
|
g_page_addr = page_addr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printk("page addr set fail\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!dummy_read(pRegs))
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if(sw_get_spi_status(&status))
|
||
|
{
|
||
|
status = -1;
|
||
|
index++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
while(((status & SW_STATUS_RACK) == 0) && (index < SW_MAX_TIME));
|
||
|
|
||
|
|
||
|
if(index >= SW_MAX_TIME)
|
||
|
{
|
||
|
printk("status :0x%x,SPIF !=0\n", status);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
int i;
|
||
|
unsigned char len = pRegs->len;
|
||
|
char temp_rx[len + 2];
|
||
|
char temp_tx[len + 2];
|
||
|
struct spi_transfer t;
|
||
|
struct spi_message m;
|
||
|
|
||
|
memset(temp_rx , 0, len + 2);
|
||
|
memset(temp_tx , 0, len + 2);
|
||
|
|
||
|
temp_tx[0] = SW_READ_MODE;
|
||
|
temp_tx[1] = SW_SPI_DATA_REG(0);
|
||
|
|
||
|
spi_message_init(&m);
|
||
|
t.tx_buf = temp_tx;
|
||
|
t.rx_buf = temp_rx;
|
||
|
t.len = len + 2;
|
||
|
spi_message_add_tail(&t, &m);
|
||
|
|
||
|
if(spi_sync(spi, &m) < 0)
|
||
|
{
|
||
|
printk(KERN_ERR "RD error in spi operation\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < len; i++)
|
||
|
{
|
||
|
pRegs->buf[i] = temp_rx[len + 2 - 1 - i];
|
||
|
|
||
|
}
|
||
|
}
|
||
|
while(0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printk("dummy_read fail\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int sw_write_reg(PBCM_REGS pRegs)
|
||
|
{
|
||
|
unsigned int index = 0;
|
||
|
unsigned char status;
|
||
|
unsigned char page_addr = pRegs->page_addr;
|
||
|
struct spi_device* spi = DRV_GetDrvDetail()->pSPIDevice;
|
||
|
|
||
|
if(spi == NULL || pRegs == NULL)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
if(sw_get_spi_status(&status))
|
||
|
{
|
||
|
status = -1;
|
||
|
index++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
while((status & SW_STATUS_SPIF) != 0 && (index < SW_MAX_TIME));
|
||
|
|
||
|
if(index >= SW_MAX_TIME)
|
||
|
{
|
||
|
printk("status :0x%x,SPIF !=0\n", status);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// printk("page_addr:0x%x,g_page_addr:0x%x\n",page_addr,g_page_addr);
|
||
|
|
||
|
if(page_addr != g_page_addr)
|
||
|
{
|
||
|
unsigned char page_addr = pRegs->page_addr;
|
||
|
|
||
|
if(!sw_set_page_addr(page_addr))
|
||
|
{
|
||
|
g_page_addr = page_addr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printk("page addr set fail\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
int i;
|
||
|
unsigned char len = pRegs->len;
|
||
|
char temp_rx[len + 2];
|
||
|
char temp_tx[len + 2];
|
||
|
struct spi_transfer t;
|
||
|
struct spi_message m;
|
||
|
|
||
|
memset(temp_rx , 0, len + 2);
|
||
|
memset(temp_tx , 0, len + 2);
|
||
|
|
||
|
temp_tx[0] = SW_WRITE_MODE;
|
||
|
temp_tx[1] = pRegs->reg_addr;
|
||
|
|
||
|
for(i = 0; i < len; i++)
|
||
|
{
|
||
|
// printk("value[%d] = 0x%x\n",i,pRegs->buf[i]);
|
||
|
temp_tx[2 + i] = pRegs->buf[len - 1 - i];
|
||
|
}
|
||
|
|
||
|
spi_message_init(&m);
|
||
|
t.tx_buf = temp_tx;
|
||
|
t.rx_buf = temp_rx;
|
||
|
t.len = len + 2;
|
||
|
spi_message_add_tail(&t, &m);
|
||
|
|
||
|
if(spi_sync(spi, &m) < 0)
|
||
|
{
|
||
|
printk(KERN_ERR "RD error in spi operation\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
while(0);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int bcm_mir_disable(void)
|
||
|
{
|
||
|
BCM_REGS bcmRegs = {0};
|
||
|
PBCM_REGS pRegs = &bcmRegs;
|
||
|
|
||
|
memset(pRegs, 0, sizeof(BCM_REGS));
|
||
|
|
||
|
pRegs->page_addr = MIR_PORT_PAG;
|
||
|
|
||
|
pRegs->reg_addr = MIR_CAP_PORT_REG;
|
||
|
pRegs->len = 4;
|
||
|
pRegs->buf[0] = 0;
|
||
|
pRegs->buf[1] = 0;
|
||
|
pRegs->buf[2] = 0;
|
||
|
pRegs->buf[3] = 0;
|
||
|
sw_write_reg(pRegs);
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->reg_addr = EG_MIR_PORT_REG;
|
||
|
pRegs->len = 4;
|
||
|
pRegs->buf[0] = 0;
|
||
|
pRegs->buf[1] = 0;
|
||
|
pRegs->buf[2] = 0;
|
||
|
pRegs->buf[3] = 0;
|
||
|
sw_write_reg(pRegs);
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->reg_addr = ING_MIR_PORT_REG;
|
||
|
pRegs->len = 4;
|
||
|
pRegs->buf[0] = 0;
|
||
|
pRegs->buf[1] = 0;
|
||
|
pRegs->buf[2] = 0;
|
||
|
pRegs->buf[3] = 0;
|
||
|
sw_write_reg(pRegs);
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->reg_addr = MIR_CTL_REG;
|
||
|
pRegs->len = 1;
|
||
|
pRegs->buf[0] = 0;
|
||
|
sw_write_reg(pRegs);
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
static int bcm_mir_access_on(unsigned int src, unsigned int dst, MIR_REG off)
|
||
|
{
|
||
|
BCM_REGS bcmRegs = {0};
|
||
|
PBCM_REGS pRegs = &bcmRegs;
|
||
|
|
||
|
if(src >= MAX_PORT || dst >= MAX_PORT)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
memset(pRegs, 0, sizeof(BCM_REGS));
|
||
|
|
||
|
pRegs->page_addr = MIR_PORT_PAG;
|
||
|
|
||
|
pRegs->reg_addr = MIR_CAP_PORT_REG;
|
||
|
pRegs->len = 4;
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] |= (MIR_CAP_PORT(dst) >> 24) & 0xff;
|
||
|
pRegs->buf[1] |= (MIR_CAP_PORT(dst) >> 16) & 0xff;
|
||
|
pRegs->buf[2] |= (MIR_CAP_PORT(dst) >> 8) & 0xff;
|
||
|
pRegs->buf[3] |= (MIR_CAP_PORT(dst) >> 0) & 0xff;
|
||
|
sw_write_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] = 0;
|
||
|
pRegs->buf[1] = 0;
|
||
|
pRegs->buf[2] = 0;
|
||
|
pRegs->buf[3] = 0;
|
||
|
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
#if 0
|
||
|
printk("R:PAGE:%d,REG:%d,VALUE:0x%x 0x%x 0x%x 0x%x\n",
|
||
|
pRegs->page_addr,
|
||
|
pRegs->reg_addr,
|
||
|
pRegs->buf[0],
|
||
|
pRegs->buf[1],
|
||
|
pRegs->buf[2],
|
||
|
pRegs->buf[3]);
|
||
|
#endif
|
||
|
|
||
|
pRegs->reg_addr = off ;
|
||
|
pRegs->len = 4;
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] |= (MIR_CAP_PORT(src) >> 24) & 0xff;
|
||
|
pRegs->buf[1] |= (MIR_CAP_PORT(src) >> 16) & 0xff;
|
||
|
pRegs->buf[2] |= (MIR_CAP_PORT(src) >> 8) & 0xff;
|
||
|
pRegs->buf[3] |= (MIR_CAP_PORT(src) >> 0) & 0xff;
|
||
|
sw_write_reg(pRegs);
|
||
|
|
||
|
|
||
|
pRegs->buf[0] = 0;
|
||
|
pRegs->buf[1] = 0;
|
||
|
pRegs->buf[2] = 0;
|
||
|
pRegs->buf[3] = 0;
|
||
|
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
/*
|
||
|
printk("R:PAGE:%d,REG:%d,VALUE:0x%x 0x%x 0x%x 0x%x\n",
|
||
|
pRegs->page_addr,
|
||
|
pRegs->reg_addr,
|
||
|
pRegs->buf[0],
|
||
|
pRegs->buf[1],
|
||
|
pRegs->buf[2],
|
||
|
pRegs->buf[3]);
|
||
|
*/
|
||
|
|
||
|
pRegs->reg_addr = MIR_CTL_REG;
|
||
|
pRegs->len = 1;
|
||
|
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] |= (off == ING_MIR_PORT_REG ?
|
||
|
EN_IN_MIR_FLTR :
|
||
|
EN_OUT_MIR_FLTR);
|
||
|
sw_write_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] = 0;
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
//printk("R:PAGE:%d,REG:%d,VALUE:0x%x\n", pRegs->page_addr, pRegs->reg_addr, pRegs->buf[0]);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int bcm_mir_access_off(unsigned int fe, MIR_REG off)
|
||
|
{
|
||
|
BCM_REGS bcmRegs = {0};
|
||
|
PBCM_REGS pRegs = &bcmRegs;
|
||
|
|
||
|
if(fe >= MAX_PORT)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
memset(pRegs, 0, sizeof(BCM_REGS));
|
||
|
|
||
|
pRegs->page_addr = MIR_PORT_PAG;
|
||
|
pRegs->reg_addr = off;
|
||
|
pRegs->len = 4;
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] &= ~((MIR_CAP_PORT(fe) >> 24) & 0xff);
|
||
|
pRegs->buf[1] &= ~((MIR_CAP_PORT(fe) >> 16) & 0xff);
|
||
|
pRegs->buf[2] &= ~((MIR_CAP_PORT(fe) >> 8) & 0xff);
|
||
|
pRegs->buf[3] &= ~((MIR_CAP_PORT(fe) >> 0) & 0xff);
|
||
|
sw_write_reg(pRegs);
|
||
|
|
||
|
pRegs->buf[0] = 0;
|
||
|
pRegs->buf[1] = 0;
|
||
|
pRegs->buf[2] = 0;
|
||
|
pRegs->buf[3] = 0;
|
||
|
|
||
|
sw_read_reg(pRegs);
|
||
|
|
||
|
|
||
|
/*
|
||
|
printk("R:PAGE:%d,REG:%d,VALUE:0x%x 0x%x 0x%x 0x%x\n",
|
||
|
pRegs->page_addr,
|
||
|
pRegs->reg_addr,
|
||
|
pRegs->buf[0],
|
||
|
pRegs->buf[1],
|
||
|
pRegs->buf[2],
|
||
|
pRegs->buf[3]);
|
||
|
*/
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
int bcm_mir_out_on(unsigned int src, unsigned int dst)
|
||
|
{
|
||
|
return bcm_mir_access_on(src, dst, ING_MIR_PORT_REG);
|
||
|
}
|
||
|
|
||
|
int bcm_mir_in_on(unsigned int src, unsigned int dst)
|
||
|
{
|
||
|
return bcm_mir_access_on(src, dst, EG_MIR_PORT_REG);
|
||
|
}
|
||
|
|
||
|
int bcm_mir_out_off(unsigned int fe)
|
||
|
{
|
||
|
return bcm_mir_access_off(fe, ING_MIR_PORT_REG);
|
||
|
}
|
||
|
|
||
|
int bcm_mir_in_off(unsigned int fe)
|
||
|
{
|
||
|
return bcm_mir_access_off(fe, EG_MIR_PORT_REG);
|
||
|
}
|
||
|
|