#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); }