You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
682 lines
22 KiB
682 lines
22 KiB
/*
|
|
* Copyright : (C) 2022 Phytium Information Technology, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
|
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
|
* either version 1.0 of the License, or (at your option) any later version.
|
|
*
|
|
* 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 Phytium Public License for more details.
|
|
*
|
|
*
|
|
* FilePath: fi3c_master.c
|
|
* Date: 2021-11-01 14:53:42
|
|
* LastEditTime: 2022-02-18 08:36:46
|
|
* Description: This file is for i3c master drivers
|
|
*
|
|
* Modify History:
|
|
* Ver Who Date Changes
|
|
* ----- ------ -------- --------------------------------------
|
|
* 1.0 zhangyan 2023/9/11 first commit
|
|
*/
|
|
|
|
/***************************** Include Files *********************************/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "fio.h"
|
|
#include "fsleep.h"
|
|
#include "fdebug.h"
|
|
#include "fi3c_hw.h"
|
|
#include "fi3c.h"
|
|
/************************** Constant Definitions *****************************/
|
|
|
|
/**************************** Type Definitions *******************************/
|
|
|
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|
#define FI3C_DEBUG_TAG "I3C_MASTER"
|
|
#define FI3C_ERROR(format, ...) FT_DEBUG_PRINT_E(FI3C_DEBUG_TAG, format, ##__VA_ARGS__)
|
|
#define FI3C_INFO(format, ...) FT_DEBUG_PRINT_I(FI3C_DEBUG_TAG, format, ##__VA_ARGS__)
|
|
#define FI3C_DEBUG(format, ...) FT_DEBUG_PRINT_D(FI3C_DEBUG_TAG, format, ##__VA_ARGS__)
|
|
|
|
/**
|
|
* @name: FI3cAddressParityCheck
|
|
* @msg: 填充Device Retaining 地址前进行校验
|
|
* @return {u32 } check_num 预校验数
|
|
* @param {u32} value 校验结果
|
|
*/
|
|
static u32 FI3cAddressParityCheck(u32 check_num)
|
|
{
|
|
u32 parity_check = 0;
|
|
u32 value = 0;
|
|
|
|
parity_check = check_num - ((check_num >>1)&0x55);
|
|
parity_check = (parity_check & 0x33) + ((parity_check >> 2)&0x33);
|
|
value = (parity_check +(parity_check>>4)) & 0x0f;
|
|
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cPrepareRR0DevAddress
|
|
* @msg: 准备Device Retaining寄存器地址部分填充内容
|
|
* @return {u32 } rr0寄存器值
|
|
* @param {uintptr} slave_address 从机地址
|
|
*/
|
|
static u32 FI3cPrepareRR0DevAddress(uintptr slave_address)
|
|
{
|
|
u32 dev_id_rr0;
|
|
dev_id_rr0 = (slave_address << 1) & 0xff;
|
|
/*RR0[7:1] = addr[6:0] */
|
|
dev_id_rr0 |= (slave_address & GENMASK(6,0)) << 1;
|
|
/*RR0[15:13] = addr[9:7] */
|
|
dev_id_rr0 |= (slave_address & GENMASK(9,7)) << 13;
|
|
if ((FI3cAddressParityCheck(slave_address & 0x7f)&1) == 0)
|
|
{
|
|
dev_id_rr0 |= 1;
|
|
}
|
|
|
|
return dev_id_rr0;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cDevPrepare
|
|
* @msg: 准备Device Retaining寄存器地址部分填充内容
|
|
* @return {FError } 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {u32} dev_id 预填写的设备号
|
|
* @param {uintptr} slave_address 从机地址
|
|
*/
|
|
static FError FI3cDevPrepare(FI3c *instance_p, u32 dev_id, uintptr slave_address)
|
|
{
|
|
u32 dev_id_rr0;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
dev_id_rr0 = FI3cPrepareRR0DevAddress(slave_address);
|
|
|
|
if (instance_p->config.trans_mode == FI3C_MODE)
|
|
{
|
|
dev_id_rr0 = dev_id_rr0|FI3C_DEV_IS_I3C;
|
|
FI3C_DEBUG("trans_mode == i3c mode ,dev_id_rr0 == %x", dev_id_rr0);
|
|
}
|
|
else
|
|
{
|
|
FI3C_DEBUG("trans_mode == i2c mode ,dev_id_rr0 == %x", dev_id_rr0);
|
|
}
|
|
|
|
FI3C_WRITE_REG32(base_addr, FI3C_DEV_ID_RR0(dev_id) , dev_id_rr0);
|
|
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterManualDevInit
|
|
* @msg: 手动添加设备信息
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {u32} dev_id 预添加的从机id号
|
|
* @param {uintptr} slave_address 从机地址
|
|
*/
|
|
FError FI3cMasterManualDevInit(FI3c *instance_p, u32 dev_id, uintptr slave_address)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 dev_ctrl_reg;
|
|
|
|
dev_ctrl_reg = FI3C_READ_REG32(base_addr, FI3C_DEVS_CTRL_OFFSET) | FI3C_DEV_ACTIVE(dev_id);
|
|
FI3C_WRITE_REG32(base_addr, FI3C_DEVS_CTRL_OFFSET, dev_ctrl_reg);
|
|
|
|
ret = FI3cDevPrepare(instance_p, dev_id, slave_address);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("Device prepare failed.");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterAllocXfer
|
|
* @msg: 为待发送Xfer分配内存空间
|
|
* @return {FI3cXferConfig *} 返回FI3cXferConfig指针
|
|
* @param {u32} *ncmd 本次需要发送的cmd数量
|
|
*/
|
|
static FI3cXferConfig *FI3cMasterAllocXfer(u32 ncmd)
|
|
{
|
|
FI3cXferConfig *xfer;
|
|
u32 size = sizeof(u32)+sizeof(FI3cCmdConfig)*ncmd;
|
|
xfer = (FI3cXferConfig *)malloc(size);
|
|
if (!xfer)
|
|
{
|
|
FI3C_ERROR("Alloc xfer memory failed!");
|
|
return NULL;
|
|
}
|
|
memset(xfer, 0, size);
|
|
|
|
return xfer;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterSendCmd
|
|
* @msg: 填充待发送cmd
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {FI3cCmdConfig} 待发送的cmd
|
|
*/
|
|
static FError FI3cMasterSendCmd(FI3c *instance_p, FI3cCmdConfig cmd)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 cmd0_reg_val = 0;
|
|
u32 cmd1_reg_val = 0;
|
|
|
|
cmd1_reg_val |= FI3C_CMD1_FIFO_CMDID(cmd.cmd_id);
|
|
if (cmd.is_ccc == FI3C_ENABLE_SEND_CCC)
|
|
{
|
|
cmd1_reg_val |= FI3C_CMD1_FIFO_CCC_CSRADDR(cmd.ccc_code);
|
|
FI3C_DEBUG("send ccc code = 0x%x", cmd.ccc_code);
|
|
}
|
|
else
|
|
{
|
|
cmd1_reg_val |= FI3C_CMD1_FIFO_CCC_CSRADDR(cmd.sub_address);
|
|
FI3C_DEBUG("send sub address = 0x%x", cmd.sub_address);
|
|
}
|
|
|
|
cmd.pl_len = cmd.rnw == FI3C_CMD0_FIFO_RNW_ENABLE ? cmd.rx_len : cmd.tx_len;
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_RNW(cmd.rnw);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_DEV_ADDR(cmd.dev_addr);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_PL_LEN(cmd.pl_len);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_IS_10B(cmd.is_10bit);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_RSBC(cmd.rsbc);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_SBCA(cmd.sbca);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_PRIV_XMIT_MODE(cmd.xmit_mode);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_BCH(cmd.bch);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_IS_CCC(cmd.is_ccc);
|
|
cmd0_reg_val |= FI3C_CMD0_FIFO_IS_DDR(cmd.is_addr);
|
|
FI3C_DEBUG("cmd0_reg_val = 0x%x, cmd1_reg_val = 0x%x", cmd0_reg_val, cmd1_reg_val);
|
|
FI3C_WRITE_REG32(base_addr, FI3C_CMD0_FIFO_OFFSET, cmd0_reg_val);
|
|
FI3C_WRITE_REG32(base_addr, FI3C_CMD1_FIFO_OFFSET, cmd1_reg_val);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterSendCCC
|
|
* @msg: 发送CCC命令
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {u8} ccc_code CCC命令代码
|
|
* @param {uintptr} slave_address 从机地址
|
|
* @param {u8} length 发送字节数
|
|
* @param {u8} mode CCC模式
|
|
* @param {u8} *buffer 待发送缓存
|
|
*/
|
|
FError FI3cMasterSendCCC(FI3c *instance_p, u8 ccc_code, uintptr slave_address, u8 length, u8 mode, u8 *buffer, boolean is_bch)
|
|
{
|
|
FError ret = FI3C_SUCCESS;
|
|
FI3cXferConfig *xfer;
|
|
|
|
xfer = FI3cMasterAllocXfer(FI3C_SEND_CCC_NUM_CMD);
|
|
if (xfer == NULL)
|
|
{
|
|
FI3C_ERROR("The send ccc code xfer allocate failed.");
|
|
goto out;
|
|
}
|
|
xfer->ncmd = FI3C_SEND_CCC_NUM_CMD;
|
|
if (is_bch == FI3C_ENABLE_SEND_BCH)
|
|
{
|
|
xfer->cmds[0].bch = FI3C_ENABLE_SEND_BCH;
|
|
}
|
|
xfer->cmds[0].tx_buf = buffer;
|
|
xfer->cmds[0].tx_len = length;
|
|
xfer->cmds[0].is_ccc = FI3C_ENABLE_SEND_CCC;
|
|
xfer->cmds[0].ccc_code = ccc_code|mode;
|
|
xfer->cmds[0].dev_addr = slave_address;
|
|
xfer->cmds[0].pl_len = length;
|
|
|
|
ret = FI3cMasterStartXfer(instance_p, xfer);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("FI3cMasterSendCCC FI3cMasterStartXfer failed.");
|
|
goto out;
|
|
}
|
|
FI3cMasterGetCmdr(instance_p, &xfer->cmds[0]);
|
|
out:
|
|
free(xfer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterGetSlaveDevInfo
|
|
* @msg: 获取当前所有设备信息
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
*/
|
|
FError FI3cMasterGetSlaveDevInfo(FI3c *instance_p)
|
|
{
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
/*dev_0 is the master device*/
|
|
for (int dev_num = 1; dev_num < FI3C_MAX_DEVICE_NUM; dev_num++)
|
|
{
|
|
FI3cDevice *dev;
|
|
dev = &instance_p->dev[dev_num];
|
|
|
|
u32 dev_rr0_reg = FI3C_READ_REG32(base_addr, FI3C_DEV_ID_RR0(dev_num));
|
|
u32 dev_rr1_reg = FI3C_READ_REG32(base_addr, FI3C_DEV_ID_RR1(dev_num));
|
|
u32 dev_rr2_reg = FI3C_READ_REG32(base_addr, FI3C_DEV_ID_RR2(dev_num));
|
|
FI3C_DEBUG("dev_rr0_reg = 0x%x, dev_rr1_reg = 0x%x, dev_rr2_reg = 0x%x", dev_rr0_reg, dev_rr1_reg, dev_rr2_reg);
|
|
|
|
dev->dev_id = dev_num;
|
|
dev->dev_cfg.is_i3c = ((dev_rr0_reg & FI3C_DEV_IS_I3C)>>9);
|
|
|
|
if (dev->dev_cfg.is_i3c)
|
|
{
|
|
dev->dev_cfg.slave_addr = ((dev_rr0_reg & FI3C_DEV_DEV_ADDR_MASK)>>1);
|
|
}
|
|
else
|
|
{
|
|
dev->dev_cfg.slave_addr = ((dev_rr0_reg & FI3C_DEV_DEV_ADDR_MASK)>>1);
|
|
dev->dev_cfg.lvr_sa_msb = ((dev_rr0_reg & FI3C_DEV_IVR_SA_MSB_MASK)>>6);
|
|
dev->dev_cfg.slave_addr |= dev->dev_cfg.lvr_sa_msb;
|
|
}
|
|
|
|
dev->dev_cfg.pib_msb = (dev_rr1_reg & FI3C_DEV_PID_MSB_MASK);
|
|
dev->dev_cfg.pid_lsb = ((dev_rr2_reg & FI3C_DEV_PID_LSB_MASK)>>16);
|
|
dev->dev_cfg.bcr = ((dev_rr2_reg & FI3C_DEV_BCR_MASK)>>8);
|
|
dev->dev_cfg.dcr_lvr = (dev_rr2_reg & FI3C_DCR_LVR_MASK);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterStartXfer
|
|
* @msg: 开始本次传输
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {FI3cXferConfig} *xfer 待发送的xfer
|
|
*/
|
|
FError FI3cMasterStartXfer(FI3c *instance_p, FI3cXferConfig *xfer)
|
|
{
|
|
FASSERT(instance_p);
|
|
FASSERT(xfer);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 ctrl_reg, i, j, write_count, read_count;
|
|
u32 *rx_fifo;
|
|
u32 *tx_fifo;
|
|
/*Alloc the rx_fifo and tx_fifo memory*/
|
|
rx_fifo = malloc(FI3C_XFER_SIZE);
|
|
tx_fifo = malloc(FI3C_XFER_SIZE);
|
|
memset(rx_fifo, 0, FI3C_XFER_SIZE);
|
|
memset(tx_fifo, 0, FI3C_XFER_SIZE);
|
|
/*Enable I3C, preparation for sending*/
|
|
ctrl_reg = FI3C_READ_REG32(base_addr, FI3C_CTRL_OFFSET);
|
|
ctrl_reg |= instance_p->config.bus_mode | FI3C_CTRL_MCS_EN | FI3C_CTRL_DEV_EN | FI3C_CTRL_MST_ACK;
|
|
FI3C_WRITE_REG32(base_addr, FI3C_CTRL_OFFSET, ctrl_reg);
|
|
for (i = 0; i < xfer->ncmd; i++)
|
|
{
|
|
memcpy(tx_fifo, xfer->cmds[i].tx_buf, xfer->cmds[i].tx_len);
|
|
if (xfer->cmds[i].tx_len % FI3C_ALIGNED_BYTE)
|
|
{
|
|
write_count = (xfer->cmds[i].tx_len / FI3C_ALIGNED_BYTE) + 1;
|
|
}
|
|
else
|
|
{
|
|
write_count = (xfer->cmds[i].tx_len / FI3C_ALIGNED_BYTE);
|
|
}
|
|
for ( j = 0; j < write_count; j++)
|
|
{
|
|
FI3C_DEBUG("start write the tx_fifo[%d] = 0x%x", j, tx_fifo[j]);
|
|
FI3C_WRITE_TX_FIFO(base_addr, tx_fifo[j]);
|
|
}
|
|
ret = FI3cMasterSendCmd(instance_p, xfer->cmds[i]);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("Send cmd failed !");
|
|
goto out;
|
|
}
|
|
/*begin sending*/
|
|
ctrl_reg |= FI3C_CTRL_MCS;
|
|
FI3C_WRITE_REG32(base_addr, FI3C_CTRL_OFFSET, ctrl_reg);
|
|
/*begin recving data*/
|
|
if (xfer->cmds[i].rnw == FI3C_CMD0_FIFO_RNW_ENABLE)
|
|
{
|
|
if (xfer->cmds[i].rx_len % FI3C_ALIGNED_BYTE)
|
|
{
|
|
|
|
read_count = (xfer->cmds[i].rx_len / FI3C_ALIGNED_BYTE) + 1;
|
|
}
|
|
else
|
|
{
|
|
read_count = (xfer->cmds[i].rx_len / FI3C_ALIGNED_BYTE);
|
|
}
|
|
for (j = 0; j < read_count; j++)
|
|
{
|
|
fsleep_millisec(1);
|
|
rx_fifo[j] = FI3C_READ_RX_FIFO(base_addr);
|
|
FI3C_DEBUG("Read the rx_fifo[%d] = 0x%x", j, rx_fifo[j]);
|
|
}
|
|
memcpy(xfer->cmds[i].rx_buf, rx_fifo, xfer->cmds[i].rx_len);
|
|
}
|
|
FI3cMasterGetCmdr(instance_p, &xfer->cmds[i]);
|
|
}
|
|
out:
|
|
free(rx_fifo);
|
|
free(tx_fifo);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterEndXfer
|
|
* @msg: 结束本次传输
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {FI3cXferConfig} *xfer 待发送的xfer
|
|
*/
|
|
FError FI3cMasterEndXfer(FI3c *instance_p)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 status0, time_out;
|
|
|
|
time_out = 0;
|
|
for (status0 = FI3C_READ_REG32(base_addr, FI3C_MST_STATUS0_OFFSET);!(status0 & FI3C_MST_STATUS0_IDLE);status0 = FI3C_READ_REG32(base_addr, FI3C_MST_STATUS0_OFFSET))
|
|
{
|
|
fsleep_millisec(10);
|
|
if (time_out++ == FI3C_TIME_OUT)
|
|
{
|
|
FI3C_ERROR("xfer timeout");
|
|
return FI3C_ERR_TIMEOUT;
|
|
}
|
|
}
|
|
/*End of xfer, clear fifo reg*/
|
|
FI3cSetEnable(base_addr, FALSE);
|
|
FI3C_WRITE_REG32(base_addr, FI3C_FLUSH_CTRL_OFFSET, FI3C_FLUSH_RX_FIFO_MASK|
|
|
FI3C_FLUSH_TX_FIFO_MASK|
|
|
FI3C_FLUSH_CMD_FIFO_MASK|
|
|
FI3C_FLUSH_CMD_RESP_MASK);
|
|
FI3cSetEnable(base_addr, TRUE);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterDataXfers
|
|
* @msg: 轮询模式下向从机传输数据
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {uintptr} slave_addr 从机地址
|
|
* @param {uintptr} sub_address 从机内部偏移地址
|
|
* @param {FI3cPriveXfer} *prive_xfer 待传输数据内容
|
|
* @param {u32} num_xfer 传输次数
|
|
*/
|
|
FError FI3cMasterDataXfers(FI3c *instance_p, uintptr slave_addr, uintptr sub_address, FI3cPriveXfer *prive_xfer, u32 num_xfer)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
FI3cXferConfig *xfer;
|
|
u32 index;
|
|
xfer = FI3cMasterAllocXfer(num_xfer);
|
|
if (!xfer)
|
|
{
|
|
FI3C_ERROR("The xfer allocate failed.");
|
|
return FI3C_ERR_INVAL_PARM;
|
|
}
|
|
xfer->ncmd = num_xfer;
|
|
for (index = 0;index < num_xfer;index++)
|
|
{
|
|
if (prive_xfer->rnw == FI3C_CMD0_FIFO_RNW_ENABLE)
|
|
{
|
|
xfer->cmds[index].rnw = FI3C_CMD0_FIFO_RNW_ENABLE;
|
|
xfer->cmds[index].rx_buf = prive_xfer[index].date_in;
|
|
xfer->cmds[index].rx_len = prive_xfer[index].length;
|
|
xfer->cmds[index].dev_addr = slave_addr;
|
|
}
|
|
else
|
|
{
|
|
xfer->cmds[index].tx_buf = prive_xfer[index].date_out;
|
|
xfer->cmds[index].tx_len = prive_xfer[index].length;
|
|
xfer->cmds[index].dev_addr = slave_addr;
|
|
}
|
|
if (instance_p->config.sub_scba == SUB_ADDRESS_16BIT)
|
|
{
|
|
xfer->cmds[index].sbca = FI3C_ENABLE_SCBA;
|
|
}
|
|
xfer->cmds[index].xmit_mode = instance_p->config.xmit_mode;
|
|
xfer->cmds[index].sub_address = sub_address;
|
|
}
|
|
|
|
ret = FI3cMasterStartXfer(instance_p, xfer);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("Start xfer failed.");
|
|
}
|
|
|
|
ret = FI3cMasterEndXfer(instance_p);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("End xfer failed.");
|
|
}
|
|
free(xfer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterWriteData
|
|
* @msg: 轮询模式下向从机写入数据
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {uintptr} slave_addr 从机地址
|
|
* @param {uintptr} sub_address 从机内部偏移地址
|
|
* @param {u8} *write_buf 数据缓存
|
|
* @param {u32} length 传输字节长度
|
|
*/
|
|
FError FI3cMasterWriteData(FI3c *instance_p, uintptr slave_address, uintptr sub_address, u8* write_buf, u8 byte_len)
|
|
{
|
|
FASSERT(instance_p);
|
|
FASSERT(byte_len <= FI3C_XFER_MAX_BYTE_LEN);
|
|
FError ret = FI3C_SUCCESS;
|
|
FI3cPriveXfer *prive_xfer;
|
|
u32 num_xfer = FI3C_CMD_SEND_TIMES;
|
|
u32 i;
|
|
|
|
prive_xfer = malloc(sizeof(FI3cPriveXfer));
|
|
memset(prive_xfer, 0, sizeof(FI3cPriveXfer));
|
|
FI3C_DEBUG("Write data byte len = %d.", byte_len);
|
|
prive_xfer[0].length = byte_len;
|
|
|
|
/*i3c mode requires sending the address once first*/
|
|
if (instance_p->config.trans_mode == FI3C_MODE)
|
|
{
|
|
if (instance_p->config.sub_scba == SUB_ADDRESS_16BIT)
|
|
{
|
|
for (i = byte_len; i > 1; i--)
|
|
{
|
|
write_buf[i] = write_buf[i - 2];
|
|
}
|
|
write_buf[0] = sub_address;
|
|
write_buf[1] = sub_address >> 8;
|
|
}
|
|
else
|
|
{
|
|
for (i = byte_len; i > 0; i--)
|
|
{
|
|
write_buf[i] = write_buf[i - 1];
|
|
}
|
|
write_buf[0] = sub_address;
|
|
}
|
|
}
|
|
prive_xfer[0].date_out = write_buf;
|
|
/*start write data*/
|
|
ret = FI3cMasterDataXfers(instance_p, slave_address, sub_address, prive_xfer, num_xfer);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("Write failed.");
|
|
}
|
|
free(prive_xfer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterReadData
|
|
* @msg: 轮询模式下从从机读出数据
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {uintptr} slave_addr 从机地址
|
|
* @param {uintptr} sub_address 从机内部偏移地址
|
|
* @param {u8} *read_buf 数据缓存
|
|
* @param {u32} length 传输字节长度
|
|
*/
|
|
FError FI3cMasterReadData(FI3c *instance_p, uintptr slave_address, uintptr sub_address, u8* read_buf, u8 byte_len)
|
|
{
|
|
FASSERT(instance_p);
|
|
FASSERT(byte_len <= FI3C_XFER_MAX_BYTE_LEN);
|
|
FError ret = FI3C_SUCCESS;
|
|
FI3cPriveXfer *prive_xfer;
|
|
u32 num_xfer = FI3C_CMD_SEND_TIMES;
|
|
|
|
prive_xfer = malloc(sizeof(FI3cPriveXfer));
|
|
memset(prive_xfer, 0, sizeof(FI3cPriveXfer));
|
|
FI3C_DEBUG("Read data byte len = %d.", byte_len);
|
|
prive_xfer[0].rnw = FI3C_CMD0_FIFO_RNW_ENABLE;
|
|
prive_xfer[0].length = byte_len;
|
|
prive_xfer[0].date_in = read_buf;
|
|
|
|
/*start read data*/
|
|
ret = FI3cMasterDataXfers(instance_p, slave_address, sub_address, prive_xfer, num_xfer);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("Read failed.");
|
|
}
|
|
|
|
free(prive_xfer);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterGetCmdr
|
|
* @msg: 读取已发送命令,从机返回内容
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {FI3cCmdConfig} 已发送命令
|
|
*/
|
|
FError FI3cMasterGetCmdr(FI3c *instance_p, FI3cCmdConfig *cmd)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 cmdr_reg, cmd_id, xfer_bytes, error;
|
|
|
|
cmdr_reg = FI3C_READ_REG32(base_addr, FI3C_CMDR_OFFSET);
|
|
cmd_id = cmdr_reg & FI3C_CMDR_CMDID_MASK;
|
|
xfer_bytes = (cmdr_reg & FI3C_CMDR_XFER_BYTES_MASK) >> 8;
|
|
error = (cmdr_reg & FI3C_CMDR_ERROR_MASK) >> 24;
|
|
if (error != 0)
|
|
{
|
|
cmd->error = error;
|
|
FI3C_DEBUG("Error occurred! cmd_id = %d, xfer_bytes = %d, error = %x", cmd_id, xfer_bytes, error);
|
|
}
|
|
else
|
|
{
|
|
FI3C_DEBUG("No error occurred! cmd_id = %d, xfer_bytes = %d", cmd_id, xfer_bytes);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterEnableIBI
|
|
* @msg: 使能带内中断
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {u32} 目标设备ID号
|
|
*/
|
|
FError FI3cMasterEnableIBI(FI3c *instance_p, u32 dev_id)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 sir_map_reg = 0, sir_config = 0;
|
|
|
|
sir_map_reg = FI3C_READ_REG32(base_addr, FI3C_SIR_MAP_DEV_REG(dev_id));
|
|
sir_map_reg &= ~FI3C_SIR_MAP_DEV_CONF_MASK(dev_id);
|
|
sir_config = FI3C_SIR_MAP_DEV_ROLE(instance_p->dev[dev_id].dev_cfg.bcr >> 6);
|
|
sir_config |= FI3C_SIR_MAP_DEV_DA(instance_p->dev[dev_id].dev_cfg.slave_addr);
|
|
sir_config |= FI3C_SIR_MAP_DEV_PL(FI3C_XFER_MAX_BYTE_LEN);
|
|
sir_config |= FI3C_SIR_MAP_DEV_ACK;
|
|
|
|
if (instance_p->dev[dev_id].dev_cfg.bcr & FI3C_BCR_MAX_DATA_SPEED_LIM)
|
|
{
|
|
sir_config |= FI3C_SIR_MAP_DEV_SLOW;
|
|
}
|
|
sir_map_reg |= FI3C_SIR_MAP_DEV_CONF(dev_id, sir_config);
|
|
|
|
FI3C_WRITE_REG32(base_addr, FI3C_SIR_MAP_DEV_REG(dev_id), sir_map_reg);
|
|
|
|
ret = FI3cMasterSendCCC(instance_p, FI3C_ENEC_DC_CCC_CMD, instance_p->dev[dev_id].dev_cfg.slave_addr, 0, 0, NULL, 0);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("send ccc ENEC failed!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterDisableIBI
|
|
* @msg: 关闭带内中断
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {u32} 目标设备ID号
|
|
*/
|
|
FError FI3cMasterDisableIBI(FI3c *instance_p, u32 dev_id)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 sir_map_reg = 0;
|
|
|
|
FI3cMasterSendCCC(instance_p, FI3C_DISEC_DC_CCC_CMD, instance_p->dev[dev_id].dev_cfg.slave_addr, 0, 0, NULL, 0);
|
|
if (ret != FI3C_SUCCESS)
|
|
{
|
|
FI3C_ERROR("send ccc DISEC failed!");
|
|
}
|
|
|
|
sir_map_reg = FI3C_READ_REG32(base_addr, FI3C_SIR_MAP_DEV_REG(dev_id));
|
|
sir_map_reg &= ~FI3C_SIR_MAP_DEV_CONF_MASK(dev_id);
|
|
sir_map_reg |= FI3C_SIR_MAP_DEV_CONF(dev_id, FI3C_SIR_MAP_DEV_DA(0x7e));
|
|
|
|
FI3C_WRITE_REG32(base_addr, FI3C_SIR_MAP_DEV_REG(dev_id), sir_map_reg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @name: FI3cMasterEnableHotJoin
|
|
* @msg: 使能热加入处理
|
|
* @return {FError} 返回错误码
|
|
* @param {FI3c} *instance_p I3C驱动实例数据
|
|
* @param {u32} 目标设备ID号
|
|
*/
|
|
FError FI3cMasterEnableHotJoin(FI3c *instance_p)
|
|
{
|
|
FASSERT(instance_p);
|
|
FError ret = FI3C_SUCCESS;
|
|
uintptr base_addr = instance_p->config.base_addr;
|
|
u32 ctrl_reg;
|
|
|
|
ctrl_reg = FI3C_READ_REG32(base_addr, FI3C_CTRL_OFFSET);
|
|
ctrl_reg |= FI3C_CTRL_JI_ACK | FI3C_CTRL_DEV_EN;
|
|
FI3C_WRITE_REG32(base_addr, FI3C_CTRL_OFFSET, ctrl_reg);
|
|
|
|
return ret;
|
|
}
|