Commit 6a3afb26 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk Committed by Alessandro Rubini

[switch-optimization]: support for single i2c fpga master driving 3 multiplexed i2c interfaces

Requires modified HDL which uses single xwb_i2c_master to access all 3
I2C interfaces (MiniBackplane_I2C0, MiniBackplane_I2C1, Sensors_I2C).
parent fc3f8432
......@@ -47,7 +47,8 @@ static int is_cpu_pwn = 0;
static int enable_d0 = 0;
static i2c_fpga_reg_t fpga_sensors_bus_master = {
.base_address = FPGA_I2C_SENSORS_ADDRESS,
.base_address = FPGA_I2C_ADDRESS,
.if_num = FPGA_I2C_SENSORS_IFNUM,
.prescaler = 500,
};
......
......@@ -10,35 +10,44 @@
int i2c_fpga_reg_init_bus(struct i2c_bus *bus)
{
i2c_fpga_reg_t *priv;
if (!bus->type_specific) {
printf("no type specific structure provided\n");
return -1;
}
if (bus->type != I2C_BUS_TYPE_FPGA_REG) {
printf("type doesn't match I2C_BUS_TYPE_FPGA_REG(%d): %d\n", I2C_BUS_TYPE_FPGA_REG, bus->type);
return -1;
}
priv = (i2c_fpga_reg_t *)bus->type_specific;
bus->transfer = i2c_fpga_reg_transfer;
bus->scan = i2c_fpga_reg_scan;
_fpga_writel(priv->base_address + FPGA_I2C_REG_CTR, 0);
_fpga_writel(priv->base_address + FPGA_I2C_REG_PREL, priv->prescaler & 0xFF);
_fpga_writel(priv->base_address + FPGA_I2C_REG_PREH, priv->prescaler >> 8);
_fpga_writel(priv->base_address + FPGA_I2C_REG_CTR, CTR_EN);
if (!(_fpga_readl(priv->base_address + FPGA_I2C_REG_CTR) & CTR_EN)) {
printf("failed to read from control register\n");
return -1;
}
i2c_fpga_reg_t *priv;
if (!bus->type_specific) {
printf("no type specific structure provided\n");
return -1;
}
if (bus->type != I2C_BUS_TYPE_FPGA_REG) {
printf("type doesn't match I2C_BUS_TYPE_FPGA_REG(%d): %d\n", I2C_BUS_TYPE_FPGA_REG, bus->type);
return -1;
}
priv = (i2c_fpga_reg_t *)bus->type_specific;
bus->transfer = i2c_fpga_reg_transfer;
bus->scan = i2c_fpga_reg_scan;
_fpga_writel(priv->base_address + FPGA_I2C_REG_CTR, 0);
_fpga_writel(priv->base_address + FPGA_I2C_REG_PREL, priv->prescaler & 0xFF);
_fpga_writel(priv->base_address + FPGA_I2C_REG_PREH, priv->prescaler >> 8);
_fpga_writel(priv->base_address + FPGA_I2C_REG_CTR, CTR_EN);
return 0;
if (!(_fpga_readl(priv->base_address + FPGA_I2C_REG_CTR) & CTR_EN)) {
printf("failed to read from control register\n");
return -1;
}
return 0;
}
static void mi2c_sel_if(uint32_t fpga_address, int num, int use)
{
if (use) {//assign i2c i/f to i2c master
_fpga_writel(fpga_address + FPGA_I2C_REG_IFS, IFS_BUSY | (num & 0x0F));
}
else { //release i2c i/f
_fpga_writel(fpga_address + FPGA_I2C_REG_IFS, 0);
}
}
static void mi2c_wait_busy(uint32_t fpga_address)
{
......@@ -49,119 +58,131 @@ static void mi2c_wait_busy(uint32_t fpga_address)
//@return: 1 - ACK, 0 - NAK
static int mi2c_start(uint32_t fpga_address, uint32_t i2c_address, uint32_t mode)
{
i2c_address = (i2c_address << 1) & 0xFF;
if (mode == I2C_READ)
i2c_address |= 1;
i2c_address = (i2c_address << 1) & 0xFF;
if (mode == I2C_READ)
i2c_address |= 1;
_fpga_writel(fpga_address + FPGA_I2C_REG_TXR, i2c_address); //set address
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, CR_STA | CR_WR); //write to control register start write
mi2c_wait_busy(fpga_address); //wait till transfer is completed
uint32_t result = _fpga_readl(fpga_address + FPGA_I2C_REG_SR);
// printf("addr = %02x, result = %02x\n", i2c_address>>1, result);
return (result & SR_RXACK) ? 0 : 1;
_fpga_writel(fpga_address + FPGA_I2C_REG_TXR, i2c_address); //set address
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, CR_STA | CR_WR); //write to control register start write
mi2c_wait_busy(fpga_address); //wait till transfer is completed
uint32_t result = _fpga_readl(fpga_address + FPGA_I2C_REG_SR);
// printf("addr = %02x, result = %02x\n", i2c_address>>1, result);
return (result & SR_RXACK) ? 0 : 1;
}
//0 - nak, 1 - ack
static int mi2c_write_byte(uint32_t fpga_address, uint8_t data, uint32_t last)
{
uint32_t cmd = CR_WR;
if (last)
cmd |= CR_STO; //if it's last byte issue stop condition after sending byte
_fpga_writel(fpga_address + FPGA_I2C_REG_TXR, data); //write into txd register the byte
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, cmd); //write command
mi2c_wait_busy(fpga_address);
// return 1;
return !(_fpga_readl(fpga_address + FPGA_I2C_REG_SR) & SR_RXACK);
uint32_t cmd = CR_WR;
if (last)
cmd |= CR_STO; //if it's last byte issue stop condition after sending byte
_fpga_writel(fpga_address + FPGA_I2C_REG_TXR, data); //write into txd register the byte
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, cmd); //write command
mi2c_wait_busy(fpga_address);
return !(_fpga_readl(fpga_address + FPGA_I2C_REG_SR) & SR_RXACK);
}
static int mi2c_read_byte(uint32_t fpga_address, uint32_t last)
{
uint32_t cmd = CR_RD;
if (last)
cmd |= CR_STO | CR_ACK; //CR_ACK means DO NOT SEND ACK
uint32_t cmd = CR_RD;
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, cmd);
mi2c_wait_busy(fpga_address);
return _fpga_readl(fpga_address + FPGA_I2C_REG_RXR); //read byte from rx register
if (last)
cmd |= CR_STO | CR_ACK; //CR_ACK means DO NOT SEND ACK
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, cmd);
mi2c_wait_busy(fpga_address);
return _fpga_readl(fpga_address + FPGA_I2C_REG_RXR); //read byte from rx register
}
int32_t i2c_fpga_reg_scan(struct i2c_bus* bus, uint32_t i2c_address)
{
if (!bus)
return I2C_NULL_PARAM;
if (bus->type != I2C_BUS_TYPE_FPGA_REG)
return I2C_BUS_MISMATCH;
i2c_fpga_reg_t* ts = (i2c_fpga_reg_t*)bus->type_specific;
uint32_t fpga_address = ts->base_address;
//start condition and wait for result
int ack = mi2c_start(fpga_address, i2c_address, I2C_READ);
if (ack) {
// stop condition and wait for result
_fpga_writel(fpga_address + FPGA_I2C_REG_TXR, 0);
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, CR_STO | CR_WR);
mi2c_wait_busy(fpga_address);
// printf("address: %02X has a device\n", i2c_address);
return 1;
}
return 0;
if (!bus)
return I2C_NULL_PARAM;
if (bus->type != I2C_BUS_TYPE_FPGA_REG)
return I2C_BUS_MISMATCH;
i2c_fpga_reg_t* ts = (i2c_fpga_reg_t*)bus->type_specific;
uint32_t fpga_address = ts->base_address;
//set the i2c i/f num
mi2c_sel_if(fpga_address, ts->if_num, 1);
//start condition and wait for result
int ack = mi2c_start(fpga_address, i2c_address, I2C_READ);
if (ack) {
// stop condition and wait for result
_fpga_writel(fpga_address + FPGA_I2C_REG_TXR, 0);
_fpga_writel(fpga_address + FPGA_I2C_REG_CR, CR_STO | CR_WR);
mi2c_wait_busy(fpga_address);
//printf("address: %02X has a device\n", i2c_address);
mi2c_sel_if(fpga_address, ts->if_num, 0); //detach I2C master from I2C i/f
return 1;
}
mi2c_sel_if(fpga_address, ts->if_num, 0); //detach I2C master from I2C i/f
return 0;
}
int32_t i2c_fpga_reg_transfer(struct i2c_bus* bus, uint32_t i2c_address, uint32_t to_write, uint32_t to_read, uint8_t* data)
{
if (!bus)
return I2C_NULL_PARAM;
if (bus->type != I2C_BUS_TYPE_FPGA_REG)
return I2C_BUS_MISMATCH;
i2c_fpga_reg_t* ts = (i2c_fpga_reg_t*)bus->type_specific;
uint32_t fpga_address = ts->base_address;
int ack = 0;
int sent = 0;
int rcvd = 0;
int b;
if (!bus)
return I2C_NULL_PARAM;
if (bus->type != I2C_BUS_TYPE_FPGA_REG)
return I2C_BUS_MISMATCH;
if (to_write)
{
ack = mi2c_start(fpga_address, i2c_address, I2C_WRITE);
if (!ack) //NAK
return I2C_DEV_NOT_FOUND;
int last = to_write-1;
for (b = 0; b < to_write; b++)
{
ack = mi2c_write_byte(fpga_address, data[b], b == last);
if (!ack)
return I2C_NO_ACK_RCVD;
sent++;
}
}
i2c_fpga_reg_t* ts = (i2c_fpga_reg_t*)bus->type_specific;
uint32_t fpga_address = ts->base_address;
int ack = 0;
int sent = 0;
int rcvd = 0;
int b;
mi2c_sel_if(fpga_address, ts->if_num, 1);
if (to_write) {
ack = mi2c_start(fpga_address, i2c_address, I2C_WRITE);
if (!ack) { //NAK
mi2c_sel_if(fpga_address, ts->if_num, 0);
return I2C_DEV_NOT_FOUND;
}
int last = to_write-1;
for (b = 0; b < to_write; b++) {
ack = mi2c_write_byte(fpga_address, data[b], b == last);
if (!ack) {
mi2c_sel_if(fpga_address, ts->if_num, 0);
return I2C_NO_ACK_RCVD;
}
sent++;
}
}
if (to_read)
{
ack = mi2c_start(fpga_address, i2c_address, I2C_READ);
if (!ack) //NAK
return I2C_DEV_NOT_FOUND;
int last = to_read-1;
for (b = 0; b < to_read; b++)
{
data[b] = mi2c_read_byte(fpga_address, b == last);
rcvd++;
}
}
return sent + rcvd;
if (to_read) {
ack = mi2c_start(fpga_address, i2c_address, I2C_READ);
if (!ack) { //NAK
mi2c_sel_if(fpga_address, ts->if_num, 0);
return I2C_DEV_NOT_FOUND;
}
int last = to_read-1;
for (b = 0; b < to_read; b++)
{
data[b] = mi2c_read_byte(fpga_address, b == last);
rcvd++;
}
}
mi2c_sel_if(fpga_address, ts->if_num, 0);
return sent + rcvd;
}
......@@ -16,6 +16,7 @@
#define FPGA_I2C_REG_RXR 0x0C
#define FPGA_I2C_REG_CR 0x10
#define FPGA_I2C_REG_SR 0x10
#define FPGA_I2C_REG_IFS 0x14
#define CTR_EN (1<<7)
#define CR_STA (1<<7)
......@@ -25,14 +26,17 @@
#define CR_ACK (1<<3)
#define SR_RXACK (1<<7)
#define SR_TIP (1<<1)
#define IFS_BUSY (1<<7)
#define FPGA_I2C0_ADDRESS 0x54000
#define FPGA_I2C1_ADDRESS 0x55000
#define FPGA_I2C_SENSORS_ADDRESS 0x56000
#define FPGA_I2C_ADDRESS 0x54000
#define FPGA_I2C0_IFNUM 0
#define FPGA_I2C1_IFNUM 1
#define FPGA_I2C_SENSORS_IFNUM 2
typedef struct
{
uint32_t base_address;
uint32_t if_num;
uint32_t prescaler;
} i2c_fpga_reg_t;
......
......@@ -95,12 +95,14 @@ uint32_t pca9554_masks[] = {
/* The two FPGA i2c masters */
i2c_fpga_reg_t fpga_bus0_reg = {
.base_address = FPGA_I2C0_ADDRESS,
.base_address = FPGA_I2C_ADDRESS,
.if_num = FPGA_I2C0_IFNUM,
.prescaler = 500,
};
i2c_fpga_reg_t fpga_bus1_reg = {
.base_address = FPGA_I2C1_ADDRESS,
.base_address = FPGA_I2C_ADDRESS,
.if_num = FPGA_I2C1_IFNUM,
.prescaler = 500,
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment