/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2020 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPELâ„¢ DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK. Lattice grants permission to use this code pursuant to the terms of the Lattice Propel License Agreement. DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #include "smbus_mailbox.h" #include "pic.h" #include unsigned char smbus_i2c_slave_init(struct smbus_slave_instance *this_smbus_slave_inst, unsigned int base_addr, unsigned int slave_addr, unsigned int int_en) { volatile struct smbus_slave_dev *i2c; if (NULL == this_smbus_slave_inst) { return 1; } this_smbus_slave_inst->base = base_addr; i2c = (volatile struct smbus_slave_dev *) (this_smbus_slave_inst->base); i2c->control |= I2C_RESET; // reset the i2c device i2c->slvadr_l = slave_addr; i2c->control = 0; i2c->tgt_byte_cnt = 0x0; i2c->int_enable1 =int_en; return 0; } void delay2() { unsigned int i; for(i=0;i<10;i++){//170 } } unsigned char smbus_i2c_write_data(struct smbus_slave_instance *this_smbus_slave_inst, unsigned char *buffer, unsigned int len) { if (NULL == this_smbus_slave_inst) { return 1; } volatile struct smbus_slave_dev *i2c = (struct smbus_slave_dev *) this_smbus_slave_inst->base; unsigned char i = 0; i2c->tgt_byte_cnt = len; for(i=0; ififo_status & TX_FIFO_FULL) == 0) { i2c->wr_rd_data = buffer[i]; } } i2c->control = TX_FIFO_EN; while((i2c->int_status1 & STOP_DET_INT) != STOP_DET_INT) { if((i2c->int_status2 & 0x20) == 0x20 || (i2c->int_status2 & 0x40) == 0x40 ) { break; } } i2c->int_status1 = 0xFF; ///clear return 0; } unsigned char smbus_i2c_stretch_off(volatile struct smbus_slave_dev *i2c) { if (NULL == i2c) { return 1; } i2c->control = TX_FIFO_EN; i2c->int_enable1 = RX_FIFO_READY_INT; return 0; } unsigned char smbus_i2c_alert(volatile struct smbus_slave_dev *i2c, unsigned char alert_en) { if (NULL == i2c) { return 1; } if(alert_en) { i2c->smb_control |= SMB_ALERT; } else { i2c->smb_control &= ~SMB_ALERT; } return 0; } void delay1() { unsigned int i; for(i=0;i<3500;i++){//350 } } void I2C_SLAVE_ISR(void *ctx) { volatile struct smbus_slave_instance *i2c_ctx = (struct smbus_slave_instance *) ctx; volatile struct smbus_slave_dev *i2c = (struct smbus_slave_dev *) i2c_ctx->base; unsigned char i=0; unsigned int status=0; if((i2c->int_status1 & RX_FIFO_READY_INT) == RX_FIFO_READY_INT) { i2c->int_enable1 = 0; //DISABLE INT i2c_ctx->length = 0; while(1) { if((i2c->int_status1 & STOP_DET_INT) == STOP_DET_INT) { break; } status = i2c->int_status2; if((status & STATUS_VALID) ==STATUS_VALID) { if((status & READ_VALID) ==READ_VALID) { i2c_ctx->status = READ; i2c->control = TX_FIFO_EN |CLK_STRETCH_EN; } else { i2c_ctx->status = WRITE; } break; } } i2c_ctx->rx_buffer[i++] = i2c->wr_rd_data; i2c_ctx->length = i2c_ctx->length + 1; if(i2c_ctx->status == WRITE) { while((i2c->int_status1 & STOP_DET_INT) != STOP_DET_INT) { status = i2c->int_status2; if((status & 0x20) == 0x20 || (status & 0x40) == 0x40 ) { //i2c->control = 0x24;//reset break; } } while((i2c->fifo_status & RX_FIFO_EMPTY) ==0x0) { i2c_ctx->rx_buffer[i++] = i2c->wr_rd_data; i2c_ctx->length = i2c_ctx->length + 1; } } } i2c->int_status1 = 0xFF; //clear i2c->int_status2 = 0xFF; //clear i2c->int_enable1 = RX_FIFO_READY_INT; //ENABLE INT } void SMBUS_SLAVE_ISR(void *ctx) { volatile struct smbus_slave_instance *i2c_ctx = (struct smbus_slave_instance *) ctx; volatile struct smbus_slave_dev *i2c = (struct smbus_slave_dev *) i2c_ctx->base; if(i2c->int_status1 & STOP_DET_INT) { i2c->int_status1 = STOP_DET_INT; if((i2c->fifo_status & RX_FIFO_EMPTY) ==0x0) { i2c_ctx->length = 0; while((i2c->fifo_status & RX_FIFO_EMPTY) ==0x0) { i2c_ctx->rx_buffer[i2c_ctx->length] = i2c->wr_rd_data; i2c_ctx->length++; } i2c_ctx->status = RCVD; } } //printf("\n i2c_data2= %x \r\n", i2c_ctx->length); if(i2c->int_status2 & (STOP_ERR_INT | START_ERR_INT)) { i2c->int_status2 = (STOP_ERR_INT | START_ERR_INT); i2c->control |= I2C_RESET; // reset the i2c device } i2c->int_status1|=0xff; ///clear i2c->control = 0; } unsigned char smbus_i2c_master_init(struct smbus_master_instance *this_smbus_master_inst, unsigned int base_addr, unsigned int slave_addr) { if (NULL == this_smbus_master_inst) { return 1; } this_smbus_master_inst->base = base_addr + SMBUS_M_SHIFT; this_smbus_master_inst->slave_addr = slave_addr; return 0; } int smbus_mailbox_write_data_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { if ((i2c->fifo_status & 0x10) != 0) // tx_fifo is full return -1; else { i2c->wr_rd_data = (unsigned int) wbyte; return 0; } } int smbus_mailbox_read_data_register(volatile struct smbus_slave_dev *i2c, unsigned char *rbyte) { if ((i2c->fifo_status & 0x01) ==1) // rx_fifo is empty return -1; else { *rbyte = i2c->wr_rd_data; return 0; } } void smbus_mailbox_write_slave_address_register(volatile struct smbus_slave_dev *i2c, unsigned short slv_id) { unsigned char byte_l, byte_h; byte_l = (unsigned char)(slv_id & 0x007F); // get 7 bits byte_h = (unsigned char)((slv_id & 0x0700)>>8); // get 3 bits i2c->slvadr_l = (unsigned int) byte_l; i2c->slvadr_h = (unsigned int) byte_h; } void smbus_mailbox_read_slave_address_register(volatile struct smbus_slave_dev *i2c, unsigned short *slv_id) { unsigned char *byte_ptr; byte_ptr = (unsigned char*) slv_id; byte_ptr[0] = (unsigned char)(i2c->slvadr_l & 0x7F); // get 7 bits byte_ptr[1] = (unsigned char)(i2c->slvadr_h & 0x07); // get 3 bits } void smbus_mailbox_set_control_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->control = (unsigned int) wbyte; } void smbus_mailbox_read_control_register(volatile struct smbus_slave_dev *i2c, unsigned char *rbyte) { *rbyte = (unsigned char) i2c->control; } void smbus_mailbox_read_interrupt_status1_register(volatile struct smbus_slave_dev *i2c, unsigned char *rdata) { *rdata = (unsigned char) i2c->int_status1; } void smbus_mailbox_read_interrupt_status2_register(volatile struct smbus_slave_dev *i2c, unsigned char *rdata) { *rdata = (unsigned char) i2c->int_status2; } void smbus_mailbox_write_clear_interrupt_status1_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->int_status1 = (unsigned int) wbyte; } void smbus_mailbox_write_clear_interrupt_status2_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->int_status2 = (unsigned int) wbyte; } void smbus_mailbox_write_interrupt_enable1_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->int_enable1 = (unsigned int) wbyte; } void smbus_mailbox_write_interrupt_enable2_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->int_enable2 = (unsigned int) wbyte; } void smbus_mailbox_write_interrupt_set1_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->int_set1 = (unsigned int) wbyte; } void smbus_mailbox_write_interrupt_set2_register(volatile struct smbus_slave_dev *i2c, unsigned char wbyte) { i2c->int_set2 = (unsigned int) wbyte; } void smbus_mailbox_read_fifo_status_register(volatile struct smbus_slave_dev *i2c, unsigned char *rdata) { *rdata = (unsigned char) i2c->fifo_status; } void smbus_mailbox_write_rf(struct smbus_slave_instance *this_smbus_slave_inst, unsigned char waddr, unsigned char wbyte) { unsigned int *ptr; // set the address. Shift waddr to the left by 2 since the memory is 4-byte aligned. ptr = (unsigned int *) (this_smbus_slave_inst->base + SMBUS_MAILBOX_RF_OFFSET + (waddr<<2)); // write to the register file inside SMBus Mailbox IP *ptr = (int) wbyte; } void smbus_mailbox_read_rf(struct smbus_slave_instance *this_smbus_slave_inst, unsigned char waddr, unsigned char *rbyte) { unsigned int *ptr; // set the address. Shift waddr to the left by 2 since the memory is 4-byte aligned. ptr = (unsigned int *) (this_smbus_slave_inst->base + SMBUS_MAILBOX_RF_OFFSET + (waddr<<2)); // write to the register file inside SMBus Mailbox IP *rbyte = (unsigned char) *ptr; } void reset_ip(struct smbus_master_instance *this_smbus_master_inst) { volatile struct smbus_slave_dev *device = (volatile struct smbus_slave_dev *) (this_smbus_master_inst->base - SMBUS_M_SHIFT); device->control = 0x04; ; ; ; ; device->control = 0x00; ; ; ; ; } void smbus_master_tx_addr(unsigned char addrin) { //set Prescale *((volatile unsigned int *)(SMBUS_MAILBOX0_INST_BASE_ADDR + SMBUS_M_SHIFT + SMBUS_M_PRERLO)) = 0x64; *((volatile unsigned int *)(SMBUS_MAILBOX0_INST_BASE_ADDR + SMBUS_M_SHIFT + SMBUS_M_PRERHI)) = 0x00; //enable core *((volatile unsigned int *)(SMBUS_MAILBOX0_INST_BASE_ADDR + SMBUS_M_SHIFT + SMBUS_M_CTR)) = 0x80; //drive slave address *((volatile unsigned int *)(SMBUS_MAILBOX0_INST_BASE_ADDR + SMBUS_M_SHIFT + SMBUS_M_TXR)) = addrin; //bit0 0/1==w/r *((volatile unsigned int *)(SMBUS_MAILBOX0_INST_BASE_ADDR + SMBUS_M_SHIFT + SMBUS_M_CR)) = 0x90; //(start, write) } int smbus_master_write_block(struct smbus_master_instance *this_smbus_master_inst, unsigned char *data, unsigned int size) { unsigned int check_sr; unsigned int i = 0; volatile struct smbus_master_dev *device = (volatile struct smbus_master_dev *) (this_smbus_master_inst->base); device->cr_sr = 0x1;//clear iack reset_ip(this_smbus_master_inst); do { device->cr_sr = 0x1;//clear iack check_sr = device->cr_sr; } while((check_sr) != 0x0); // initial should all zeros //set Prescale device->prerlo = 0x64; device->prerhi = 0x00; //enable core device->ctr = 0x80; //drive slave address device->txr_rxr = this_smbus_master_inst->slave_addr; //bit0 0/1==w/r device->cr_sr = 0x90; //(start, write) do { check_sr = device->cr_sr; if((check_sr&0xa4) != 0x0){//slave noack or arb lost or timeout device->cr_sr = 0x5; return -1; } if((check_sr&0x1) == 0x1){ device->cr_sr = 0x1;//clear iack } } while(check_sr&0xaf); //should only bit6=1 & bit0=1 //send data for(i = 0; i < size; i++) { //drive data device->txr_rxr = data[i]; // present data device->cr_sr = 0x10; // set command (write) do { check_sr = device->cr_sr; if((check_sr&0xa4) != 0x0){//slave noack or arb lost or timeout device->cr_sr = 0x5; return -1; } if((check_sr&0x1) == 0x1){ device->cr_sr = 0x1;//clear iack } } while(check_sr&0xaf); //should only bit6=1 & bit0=1 } //stop transfer device->cr_sr = 0x40; // set command (stop) do { check_sr = device->cr_sr; }while(check_sr & 0x00000040); // poll it until it is not busy return 0; } /* unsigned char smbus_master_write_block(unsigned char *data_in, unsigned int data_size, unsigned char addr_in) { unsigned int smbus_master_addr; unsigned int check_sr; //SMBUS 100K/0.1M: // wb_clk_i Frequency / Prescale Register = 5 times of SMBUS = 0.5M // Prescale Register = 100/0x64 volatile struct i2c_master_dev *master_dev = (struct i2c_master_dev *) (SMBUS_MAILBOX0_INST_BASE_ADDR + SMBUS_M_SHIFT); master_dev->prerlo = 0x64; master_dev->prerhi = 0x00; master_dev->ctr = 0x80; master_dev->txr_rxr = addr_in | 0x00; master_dev->cr_sr = 0x90; do { check_sr = master_dev->cr_sr; } while(check_sr & 0x00000002); // poll it until it is zero bit1: 0 = Transfer is complete //debug_io(0x02); int i = 0; for(i = 0; i < data_size; i++) { // send memory contents master_dev->txr_rxr = *(data_in + i); // present data master_dev->cr_sr = 0x10; // set command (write) // debug_io(0x05); // check tip bit do { check_sr = master_dev->cr_sr; } while(check_sr & 0x00000002); // poll it until it is zero bit1: 0 = Transfer is complete } // debug_io(0x06); master_dev->cr_sr = 0x40; // set command (stop) do { check_sr = master_dev->cr_sr; } while(check_sr & 0x00000040); // wait for done return 0; } */ unsigned char smbus_slave_read_data(unsigned char * data) { unsigned char rbyte = 0; unsigned int status =0; volatile int *rd_data_reg_ptr; rd_data_reg_ptr = (volatile int *) (0x000D0000 + 0); volatile int *fifo_status_reg_ptr; fifo_status_reg_ptr = (volatile int *) (0x000D0000 + 0x2c); volatile int *int_status_reg_ptr; int_status_reg_ptr = (volatile int *) (0x000D0000 + 0x14); volatile unsigned char int_status1; //wait real BMC sends data //clear all flag introduced before *int_status_reg_ptr = 0xFF; *fifo_status_reg_ptr = 0xFF; do { int_status1 = *int_status_reg_ptr; } while ((int_status1 & 0x40) == 0); if((*fifo_status_reg_ptr & 0x01) ==0x0) { while((*fifo_status_reg_ptr & 0x01) ==0x0) { *data = *rd_data_reg_ptr; //*data = 0x13; ++data; rbyte++; } } return rbyte; }