/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2024 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. ------------------------------------------------------------------ @version 0.1.0 ================================================================== */ #include "i3c_controller.h" #include "hal.h" #define MAX_RETRY (50) #if I3C_DEBUG #define DEBUG_PRINTF printf #else #define DEBUG_PRINTF #endif // add for I3C test extern unsigned char boot_status; /* * @brief i3c_master_init function for i3c controller. * @param : this_i3cm : handler for the controller * @param : addr : controller addr * @param : slave_nums : slave number * @return : status for this function */ uint8_t i3c_master_init(struct i3c_master_instance *this_i3cm,uint32_t addr,uint8_t mode,uint8_t clk,uint8_t slave_nums) { uint32_t clk_value; unsigned char reg_value; if (NULL == this_i3cm) { return -1; } this_i3cm->base_addr = addr; this_i3cm->devs_nums = slave_nums; /* Enable the I2C mode */ reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_CFG0, I2C_MODE_ALLOWED, I2C_MODE_ALLOWED); #ifdef ENABLE_DAA_UID reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_CFG0, EN_DAA_UID_IN_RXFIFO, EN_DAA_UID_IN_RXFIFO); #endif reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_ENABLE, 0x10);//enable all interrupt reg_8b_write(this_i3cm->base_addr | I3C_MASTER_DA_ACK_REG, 0xff); //[cw] Clear num_da_acked on initialization /* * Uncomment these code if you want to reconfigure the SCL * and open-drain clocks via software. The value written here * is n-1. Example, if the value is Propel Builder GUI is 10 * then it is 9 to be written into the register. */ //reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CLKPERIOD, 9); //10 is working (1.4 MHz) //reg_8b_write(this_i3cm->base_addr | I3C_MASTER_OPEN_DRAIN_TIMER, 0); // 1 is working value reg_8b_read(this_i3cm->base_addr | I3C_MASTER_CLKPERIOD, ®_value); printf("Sys clk register: %d\n", reg_value); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_OPEN_DRAIN_TIMER, ®_value); printf("Open drain timer register: %d\n", reg_value); return 0; } /* * @brief i3c_master_entdaa_config function for i3c controller. * @param : this_i3cm : handler for the controller * @param : slave_nums : slave number * @param : slave_addr : slave addr * @return : status for this function */ static uint8_t i3c_master_entdaa_config(struct i3c_master_instance *this_i3cm, uint8_t slave_nums, uint8_t slave_addr) { uint32_t wr_length, rd_length; uint8_t control; if (NULL == this_i3cm) { return -1; } control = CCC_IN_FRAME|STOP_IN_FRAME|START_OF_CCC; reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO,control); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO,I3C_BROADCAST_ADDR); //broadcast reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO,0x01 + slave_nums); //write length reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, I3C_CCC_ENTDAA); //ENTDAA CCC for(int i = 0; ibase_addr | I3C_MASTER_WRITE_FIFO, slave_addr++ << 1); } return 0; } /* * @brief i3c_master_daa function for i3c controller. * @param : this_i3cm : handler for the controller * @param : m : device info * @param : dyn_address : dynamic addr * @param : device_count : device count * @param : slave_addr : slave addr * @return : status for this function */ uint8_t i3c_master_daa(struct i3c_master_instance *this_i3cm,struct i3c_dev_info *m,uint8_t *dyn_address,uint32_t device_count, uint8_t slave_addr) { int retry = 0; uint64_t device_pid = 0, device_pid_shift = 0; uint8_t device_bcr,device_dcr; unsigned char read_value; int count; int cnt=0; uint32_t int_status = 0, num_da_acked = 0; if (NULL == this_i3cm) { return -1; } /* Slave address takes only 7-bit */ if (slave_addr > 127) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_DA_ACK_REG, MASK_CLEAR); //[cw] Make sure num_da_acked cleared to 0 reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); i3c_master_entdaa_config(this_i3cm, device_count, slave_addr); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); /* delayMS is defined in utils.c which auto-generated when creating RISC-V MC * software template * */ delayMS(1500); while(retry < MAX_RETRY) { retry++; reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); DEBUG_PRINTF("i3c_master_daa() - int_status=0x%x\r\n",int_status); if(int_status & I3C_INT0_COMMAND_DONE) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_COMMAND_DONE); DEBUG_PRINTF("i3c_master_daa() - I3C_INT0_COMMAND_DONE\r\n"); if(int_status & I3C_INT0_SLAVE_NACK) // wait until all slaves ACK on DAA { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_SLAVE_NACK); DEBUG_PRINTF("i3c_master_daa() - I3C_INT0_SLAVE_NACK\r\n"); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_DA_ACK_REG, (uint8_t *)&num_da_acked); DEBUG_PRINTF("i3c_master_daa() - num_da_acked=%d\r\n", num_da_acked); if (num_da_acked) { if(int_status & I3C_INT0_R_FIFO_n_EMPTY) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_R_FIFO_n_EMPTY); for(cnt=0;cnt=0;count--) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO, (uint8_t *)&read_value); device_pid_shift = (uint64_t) read_value; device_pid = device_pid | (device_pid_shift << (8*count)); } reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO,(uint8_t *)&read_value); device_bcr=read_value; reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO,(uint8_t *)&read_value); device_dcr=read_value; m[cnt].pid=device_pid; m[cnt].bcr=device_bcr; m[cnt].dcr=device_dcr; m[cnt].init_dyn_addr=*dyn_address; } break; } break; } else { return 1; } } } } if(retry < MAX_RETRY ) return 0; else return 1; } /* * @brief i3c_master_private_i3c_read function for i3c controller. * @param : this_i3cm : handler for the controller * @param : rd_buf : read buffer * @param : rd_length : read length * @param : slave_dyn_addr : slave dynamic addr * @return : status for this function */ uint8_t i3c_master_private_i3c_read(struct i3c_master_instance *this_i3cm,uint8_t *rd_buf,uint8_t rd_length,uint8_t slave_dyn_addr) { uint8_t i=0; uint32_t int_status=0; if (NULL == this_i3cm) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); //clear all pending bits //[cw] reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CFG0, 0); //ENTER I3C MODE reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CFG0, I3C_PRIV_RW_NO_7E ); //[cw] ENTER I3C MODE with no broadcast reg_8b_write(this_i3cm->base_addr | I3C_MASTER_SOFT_RESET, RX_FIFO_RST ); //[cw] Reset RX FIFO reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, STOP_IN_FRAME); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, (slave_dyn_addr << 1) | 0x1); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, rd_length); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); delayMS(1); while(1) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); if(int_status & I3C_INT0_COMMAND_DONE) { if(int_status & I3C_INT0_SLAVE_NACK) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); return 1; } else if (int_status & I3C_INT0_RD_CMD_DONE) { for(i=0; ibase_addr | I3C_MASTER_READ_FIFO, (unsigned char*) rd_buf); rd_buf++; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); return 0; } } } } /* * @brief i3c_master_private_i3c_write function for i3c controller. * @param : this_i3cm : handler for the controller * @param : wr_buf : write buffer * @param : wr_length : write length * @param : slave_dyn_addr : slave dynamic addr * @return : status for this function */ uint8_t i3c_master_private_i3c_write(struct i3c_master_instance *this_i3cm,uint8_t *wr_buf,uint8_t wr_length,uint8_t slave_dyn_addr) { uint8_t count=0; uint32_t int_status=0; if (NULL == this_i3cm) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); //clear all pending bits //[cw] reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CFG0, 0); //ENTER I3C MODE reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CFG0, I3C_PRIV_RW_NO_7E ); //[cw] ENTER I3C MODE with no broadcast reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, STOP_IN_FRAME); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, slave_dyn_addr << 1); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, wr_length); for(uint8_t i=0;ibase_addr | I3C_MASTER_WRITE_FIFO, wr_buf[i]); } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); // delayMS(1); while(1) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); DEBUG_PRINTF("\r\nI3C0: Write command done int=0x(%x).",int_status); if (int_status & I3C_INT0_COMMAND_DONE) //wait cmd done { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); if(int_status & I3C_INT0_SLAVE_NACK) { return 1; } else { return 0; } } } } /* * @brief i3c_master_private_i2c_read function for i3c controller. * @param : this_i3cm : handler for the controller * @param : rd_buf : read buffer * @param : rd_length : read length * @param : slave_dyn_addr : slave addr * @return : status for this function */ uint8_t i3c_master_private_i2c_read(struct i3c_master_instance *this_i3cm, uint8_t *rd_buf, uint8_t rd_length, uint8_t slave_dyn_addr) { uint32_t int_status=0; if (NULL == this_i3cm) { return -1; } reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_CFG0, I2C_MODE_ALLOWED, I2C_MODE_ALLOWED); // make sure I2C mode is on reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, STOP_IN_FRAME|I2C_COMMAND); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, (slave_dyn_addr << 1) | 0x1); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, rd_length); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); delayMS(1); while(1) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); if(int_status & I3C_INT0_COMMAND_DONE) { if(int_status & I3C_INT0_SLAVE_NACK) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); return 1; } else if (int_status & I3C_INT0_RD_CMD_DONE) { for(uint8_t i=0; ibase_addr | I3C_MASTER_READ_FIFO, (unsigned char*) rd_buf); rd_buf++; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); return 0; } } } } /* * @brief i3c_master_private_i2c_write function for i3c controller. * @param : this_i3cm : handler for the controller * @param : wr_buf : write buffer * @param : wr_length : write length * @param : slave_dyn_addr : slave addr * @return : status for this function */ uint8_t i3c_master_private_i2c_write(struct i3c_master_instance *this_i3cm,uint8_t *wr_buf,uint8_t wr_length,uint8_t slave_dyn_addr) { uint8_t count=0; uint32_t int_status=0; if (NULL == this_i3cm) { return -1; } reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_CFG0, I2C_MODE_ALLOWED, I2C_MODE_ALLOWED); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, STOP_IN_FRAME|I2C_COMMAND); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, slave_dyn_addr << 1); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, wr_length); for(uint8_t i=0;ibase_addr | I3C_MASTER_WRITE_FIFO, wr_buf[i]); } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); delayMS(1); while(1) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); if(int_status & I3C_INT0_COMMAND_DONE) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); if(int_status & I3C_INT0_SLAVE_NACK) { return 1; } else { return 0; } } } } /* * @brief i3c_master_private_i3c_read_handle_early_term function for i3c controller. * @param : this_i3cm : handler for the controller * @param : rd_buf : read buffer * @param : expected_rd_length : expected read length * @param : slave_dyn_addr : slave dynamic addr * @param : actual_rd_length : actual read length * @return : status for this function */ uint8_t i3c_master_private_i3c_read_handle_early_term(struct i3c_master_instance *this_i3cm,uint8_t *rd_buf,uint8_t expected_rd_length, uint8_t slave_dyn_addr, uint8_t *actual_rd_length) { uint8_t i=0; uint8_t int_status=0; uint8_t int1_status=0; if (NULL == this_i3cm) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); //clear all pending bits reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CFG0, I3C_PRIV_RW_NO_7E ); //[cw] ENTER I3C MODE with no broadcast reg_8b_write(this_i3cm->base_addr | I3C_MASTER_SOFT_RESET, RX_FIFO_RST ); //[cw] Reset RX FIFO reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, STOP_IN_FRAME); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, (slave_dyn_addr << 1) | 0x1); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, expected_rd_length); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); while(1) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA1,(uint8_t *)&int1_status); if(int_status & I3C_INT0_COMMAND_DONE) { if(int_status & I3C_INT0_SLAVE_NACK) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); return 1; } else if (int_status & I3C_INT0_RD_CMD_DONE) { for(i=0; ibase_addr | I3C_MASTER_READ_FIFO, (unsigned char*) rd_buf); rd_buf++; (*actual_rd_length)++; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); return 0; } else if (int1_status & I3C_INT1_RD_EARLY_TERM) { while (int_status & I3C_INT0_R_FIFO_n_EMPTY) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO, (unsigned char*) rd_buf); rd_buf++; (*actual_rd_length)++; reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_R_FIFO_n_EMPTY); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA1, I3C_INT1_RD_EARLY_TERM); return 0; } } } } /* * @brief i3c_master_private_i3c_write_repeated_start_read_handle_early_term function for i3c controller. * @param : this_i3cm : handler for the controller * @param : rd_buf : read buffer * @param : expected_rd_length : expected read length * @param : slave_dyn_addr : slave dynamic addr * @param : actual_rd_length : actual read length * @return : status for this function */ uint8_t i3c_master_private_i3c_write_repeated_start_read_handle_early_term(struct i3c_master_instance *this_i3cm,uint8_t *wr_buf,uint8_t wr_length,uint8_t slave_dyn_addr, uint8_t expected_rd_length, uint8_t *rd_buf, uint8_t *actual_rd_length) { uint8_t int_status=0; uint8_t int1_status=0; uint8_t i=0; if (NULL == this_i3cm) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); //clear all pending bits (except ibi related interrupt) reg_8b_write(this_i3cm->base_addr | I3C_MASTER_CFG0, I3C_PRIV_RW_NO_7E ); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, 0x00); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, slave_dyn_addr << 1); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, wr_length); for(uint8_t i=0;ibase_addr | I3C_MASTER_WRITE_FIFO, wr_buf[i]); } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, 0x06); // repeated start reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, (slave_dyn_addr << 1) | 0x1); // read address reg_8b_write(this_i3cm->base_addr | I3C_MASTER_WRITE_FIFO, expected_rd_length); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); while(1) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA1,(uint8_t *)&int1_status); if(int_status & I3C_INT0_COMMAND_DONE) { if(int_status & I3C_INT0_SLAVE_NACK) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); return 1; } else if (int_status & I3C_INT0_RD_CMD_DONE) { for(i=0; ibase_addr | I3C_MASTER_READ_FIFO, (unsigned char*) rd_buf); rd_buf++; (*actual_rd_length)++; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); return 0; } else if (int1_status & I3C_INT1_RD_EARLY_TERM) { while (int_status & I3C_INT0_R_FIFO_n_EMPTY) { reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO, (unsigned char*) rd_buf); rd_buf++; (*actual_rd_length)++; reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_R_FIFO_n_EMPTY); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA,(uint8_t *)&int_status); } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA,I3C_INT0_DEFAULT_STATUS); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA1, I3C_INT1_RD_EARLY_TERM); return 0; } } } } /* * @brief ibi init function for i3c controller. * @param : this_i3cm : handler for the controller * @return : status for this function */ uint8_t i3c_master_ibi_Init(struct i3c_master_instance *this_i3cm) { if (NULL == this_i3cm) { return -1; } unsigned char reg = 0; /* Set controller IBI auto response to 0, to prioritize IBI ACK */ reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_CFG0, 0x20, 0); /* Clear all pending bits */ reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); //enable ibi reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_INTR_ENABLE, RCVD_IBI_EN, RCVD_IBI_EN); //enable hotjoin reg_8b_modify(this_i3cm->base_addr | I3C_MASTER_INTR_ENABLE, RCVD_HOT_JOIN_EN, RCVD_HOT_JOIN_EN); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA1, ®); //Does not match the Specificaiton printf("i3c_master_ibi_Init->I3C_MASTER_INTR_STA1 = %x\n\r", reg); } /* * @brief direct ccc function for i3c controller. * @param : this_i3cm : handler for the controller * @param : slave_address : slave addr * @param : size_A : ccc length * @param : buffer_A : ccc code * @param : size_B : length of target address plus read/write flag * @param : buffer_B : target address plus read/write flag * @param : read_write : read or write * @param : return_value : read out content after ccc * @param : return_value_size : length of read out content after ccc * @return : status for this function */ uint8_t i3c_master_direct_ccc(struct i3c_master_instance *this_i3cm, uint8_t slave_address, int size_A, uint8_t *buffer_A, int size_B, uint8_t *buffer_B, uint8_t read_write, uint8_t *return_value, int *return_value_size) { int retry = 0; uint64_t device_pid = 0, device_pid_shift = 0; uint8_t device_bcr, device_dcr; unsigned char read_value; int count; int cnt = 0; uint32_t int_status = 0; unsigned char internal_buffer[] = { 0x09, 0xFC, 0x01 }; unsigned char internal_buffer_B[] = { 0x07, 0x00, 0x00 }; // write is 0 read is 1 internal_buffer_B[1] = (slave_address << 1) | read_write; //Length = number of optional bytes (B) internal_buffer_B[2] = size_B; //Length = 1+ number of optional bytes (A) internal_buffer[2] = size_A; if (NULL == this_i3cm) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_DA_ACK_REG, MASK_CLEAR);//[cw] Make sure num_da_acked cleared to 0 reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, 3, internal_buffer); fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, size_A, buffer_A); if(size_B > 0){ fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, 3, internal_buffer_B); if(buffer_B != NULL){ fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, size_B, buffer_B); } } else { fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, 2, internal_buffer_B); } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); delayMS(1500); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); if (int_status & I3C_INT0_COMMAND_DONE) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_COMMAND_DONE); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); *return_value_size=0; while(int_status & I3C_INT0_R_FIFO_n_EMPTY){ reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO,&read_value); return_value[(*return_value_size)++] = read_value; reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); } } return 0; } /* * @brief broadcast ccc function for i3c controller. * @param : this_i3cm : handler for the controller * @param : size : buffer size * @param : buffer : ccc buffer * @param : return_value : return content of ccc * @param : return_value_size : length of return content of ccc * @return : status for this function */ uint8_t i3c_master_broadcast_ccc(struct i3c_master_instance *this_i3cm, int size, unsigned char *buffer, unsigned char *return_value, int *return_value_size) { int retry = 0; uint64_t device_pid = 0, device_pid_shift = 0; uint8_t device_bcr,device_dcr; unsigned char read_value; int count; int cnt=0; uint32_t int_status = 0, num_da_acked = 0; unsigned char internal_buffer[] = {0x0D, 0xFC, 0x01}; internal_buffer[2] = size; if (NULL == this_i3cm) { return -1; } reg_8b_write(this_i3cm->base_addr | I3C_MASTER_DA_ACK_REG, MASK_CLEAR); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, 3, internal_buffer); fill_the_I3C_MASTER_WRITE_FIFO(this_i3cm, size, buffer); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_START_REG, START); delayMS(1500); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); DEBUG_PRINTF("i3c_master_broadcast_ccc() - int_status=0x%x\r\n", int_status); if (int_status & I3C_INT0_COMMAND_DONE) { reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_COMMAND_DONE); reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); *return_value_size=0; while(int_status & I3C_INT0_R_FIFO_n_EMPTY){ reg_8b_read(this_i3cm->base_addr | I3C_MASTER_READ_FIFO,&read_value); return_value[(*return_value_size)++] = read_value; reg_8b_write(this_i3cm->base_addr | I3C_MASTER_INTR_STA, I3C_INT0_DEFAULT_STATUS); reg_8b_read(this_i3cm->base_addr | I3C_MASTER_INTR_STA, (uint8_t *)&int_status); } } else { return 1; } return 0; } uint8_t fill_the_I3C_MASTER_WRITE_FIFO(struct i3c_master_instance *this_i3cm, uint32_t size, uint8_t *buffer){ uint32_t wr_length, rd_length; uint8_t control; if (NULL == this_i3cm) { return -1; } for(int i = 0; ibase_addr | I3C_MASTER_WRITE_FIFO,buffer[i]); } return 0; }