From 639cc1d02bc75f90a790a26bf5f302b28366c81d Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sat, 19 Sep 2020 17:21:36 -0700 Subject: [PATCH] Register I2C muxes and clients for NetFPGA SUME, VCU108, VCU118, VCU1525, and ZCU106 --- modules/mqnic/mqnic.h | 2 + modules/mqnic/mqnic_i2c.c | 251 +++++++++++++++++++++++++++++++++++++- 2 files changed, 249 insertions(+), 4 deletions(-) diff --git a/modules/mqnic/mqnic.h b/modules/mqnic/mqnic.h index a68c89459..e9f6595bc 100644 --- a/modules/mqnic/mqnic.h +++ b/modules/mqnic/mqnic.h @@ -110,6 +110,8 @@ struct mqnic_dev { struct i2c_adapter i2c_adapter[MQNIC_MAX_I2C_ADAPTERS]; struct mqnic_i2c_priv i2c_priv[MQNIC_MAX_I2C_ADAPTERS]; + int mod_i2c_client_count; + struct i2c_client *mod_i2c_client[MQNIC_MAX_IF]; struct i2c_client *eeprom_i2c_client; }; diff --git a/modules/mqnic/mqnic_i2c.c b/modules/mqnic/mqnic_i2c.c index 5d4e54107..c7f6b0e2a 100644 --- a/modules/mqnic/mqnic_i2c.c +++ b/modules/mqnic/mqnic_i2c.c @@ -32,6 +32,8 @@ either expressed or implied, of The Regents of the University of California. */ #include "mqnic.h" +#include +#include #include void mqnic_i2c_set_scl(void *data, int state) @@ -85,6 +87,11 @@ static const struct i2c_algo_bit_data mqnic_i2c_algo = { .timeout = 20 }; +static const struct property_entry i2c_mux_props[] = { + PROPERTY_ENTRY_BOOL("i2c-mux-idle-disconnect"), + { } +}; + static struct i2c_client *create_i2c_client(struct i2c_adapter *adapter, const char *type, int addr, const struct property_entry *props) { struct i2c_client *client; @@ -107,9 +114,27 @@ static struct i2c_client *create_i2c_client(struct i2c_adapter *adapter, const c if (!client) return NULL; + // force driver load (mainly for muxes so we can talk to downstream devices) + device_attach(&client->dev); + return client; } +static struct i2c_adapter *get_i2c_mux_channel(struct i2c_client *mux, u32 chan_id) +{ + struct i2c_mux_core *muxc; + + if (!mux) + return NULL; + + muxc = i2c_get_clientdata(mux); + + if (!muxc || chan_id >= muxc->num_adapters) + return NULL; + + return muxc->adapter[chan_id]; +} + static struct i2c_adapter *mqnic_create_i2c_adapter(struct mqnic_dev *mqnic, u8 __iomem *reg) { struct i2c_algo_bit_data *algo; @@ -156,11 +181,220 @@ static struct i2c_adapter *mqnic_create_i2c_adapter(struct mqnic_dev *mqnic, u8 int mqnic_init_i2c(struct mqnic_dev *mqnic) { struct i2c_adapter *adapter; + struct i2c_client *mux; int ret = 0; - // interface i2c interfaces - // TODO - // eeprom i2c interface + mqnic->mod_i2c_client_count = 0; + + // Interface I2C bus + switch (mqnic->board_id) { + case MQNIC_BOARD_ID_NETFPGA_SUME: + // FPGA IC12 + // TCA9548 IC31 0x74 + // CH0: SFP1 IC3 0x50 + // CH1: SFP2 IC5 0x50 + // CH2: SFP3 IC6 0x50 + // CH3: SFP4 IC8 0x50 + // CH4: DDR3 IC27 0x51 + // DDR3 IC28 0x52 + // SI5324 IC20 0x68 + // CH5: FMC + // CH6: PCON + // CH7: PMOD J11 + + request_module("i2c_mux_pca954x"); + request_module("at24"); + + // I2C adapter + adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0); + + // IC31 TCA9548 I2C MUX + mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props); + + // IC3 SFP1 + mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c02", 0x50, NULL); + + // IC5 SFP2 + mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 1), "24c02", 0x50, NULL); + + // IC6 SFP3 + mqnic->mod_i2c_client[2] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL); + + // IC8 SFP4 + mqnic->mod_i2c_client[3] = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c02", 0x50, NULL); + + mqnic->mod_i2c_client_count = 4; + + break; + case MQNIC_BOARD_ID_VCU108: + // FPGA U1 + // TCA9548 U28 0x74 + // CH0: SI570 Osc U32 0x5D + // CH1: TCA6416 Port Exp U89 0x21 + // CH2: QSFP U145 0x50 + // CH3: NC + // CH4: SI5328 U57 0x68 + // CH5: HDMI U52 0x39 + // CH6: SYSMON U1 0x32 + // CH7: NC + // PCA9544 U80 0x75 + // CH0: PMBUS + // CH1: FMC_HPC0 J22 + // CH2: FMC_HPC1 J2 + // CH3: M24C08 EEPROM U12 0x54 + + request_module("i2c_mux_pca954x"); + request_module("at24"); + + // I2C adapter + adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0); + + // U28 TCA9548 I2C MUX + mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props); + + // U145 QSFP + mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL); + + // U80 PCA9544 I2C MUX + mux = create_i2c_client(adapter, "pca9544", 0x75, i2c_mux_props); + + // U12 I2C EEPROM + mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c08", 0x54, NULL); + + mqnic->mod_i2c_client_count = 1; + + break; + case MQNIC_BOARD_ID_VCU118: + // FPGA U1 + // TCA9548 U28 0x74 + // CH0: SI570 Osc U32 0x5D + // CH1: NC + // CH2: QSFP1 U145 0x50 + // CH3: QSFP2 U123 0x50 + // CH4: SI5328 U57 0x68 + // CH5: SI570 Osc U18 0x5D + // CH6: SYSMON U1 0x32 + // CH7: FIREFLY J6 0x50 + // TCA9548 U80 0x75 + // CH0: PMBUS + // CH1: FMCP_HSPC J22 + // CH2: FMC_HPC1 J2 + // CH3: M24C08 EEPROM U12 0x54 + // CH4: INA_PMBUS + // CH5: SI570 Osc U38 0x5D + // CH6: NC + // CH7: NC + + request_module("i2c_mux_pca954x"); + request_module("at24"); + + // I2C adapter + adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0); + + // U28 TCA9548 I2C MUX + mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props); + + // U145 QSFP1 + mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL); + + // U123 QSFP2 + mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c02", 0x50, NULL); + + // U80 PCA9548 I2C MUX + mux = create_i2c_client(adapter, "pca9548", 0x75, i2c_mux_props); + + // U12 I2C EEPROM + mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c08", 0x54, NULL); + + mqnic->mod_i2c_client_count = 2; + + break; + case MQNIC_BOARD_ID_VCU1525: + // FPGA U13 + // PCA9546 U28 0x74 + // CH0: QSFP0 J7 0x50 + // CH1: QSFP1 J9 0x50 + // CH2: M24C08 EEPROM U62 0x54 + // SI570 Osc U14 0x5D + // CH3: SYSMON U13 0x32 + + request_module("i2c_mux_pca954x"); + request_module("at24"); + + // I2C adapter + adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0); + + // U28 TCA9546 I2C MUX + mux = create_i2c_client(adapter, "pca9546", 0x74, i2c_mux_props); + + // J7 QSFP0 + mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c02", 0x50, NULL); + + // J9 QSFP1 + mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 1), "24c02", 0x50, NULL); + + // U12 I2C EEPROM + mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c08", 0x54, NULL); + + mqnic->mod_i2c_client_count = 2; + + break; + case MQNIC_BOARD_ID_ZCU106: + // FPGA U1 / MSP430 U41 I2C0 + // TCA6416 U61 0x21 + // TCA6416 U97 0x20 + // PCA9544 U60 0x75 + // CH0: PS_PMBUS + // CH1: PL_PMBUS + // CH2: MAXIM_PMBUS + // CH3: SYSMON U1 0x32 + // FPGA U1 / MSP430 U41 I2C1 + // TCA9548 U34 0x74 + // CH0: M24C08 EEPROM U23 0x54 + // CH1: SI5341 U69 0x36 + // CH2: SI570 Osc U42 0x5D + // CH3: SI570 Osc U56 0x5D + // CH4: SI5328 U20 0x68 + // CH5: NC + // CH6: NC + // CH7: NC + // TCA9548 U135 0x75 + // CH0: FMC_HPC0 J5 + // CH1: FMC_HPC1 J4 + // CH2: SYSMON U1 0x32 + // CH3: DDR4 SODIMM 0x51 + // CH4: NC + // CH5: NC + // CH6: SFP1 P2 0x50 + // CH7: SFP0 P1 0x50 + + request_module("i2c_mux_pca954x"); + request_module("at24"); + + // I2C adapter + adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0); + + // U34 TCA9548 I2C MUX + mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props); + + // U23 I2C EEPROM + mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c08", 0x54, NULL); + + // U135 TCA9548 I2C MUX + mux = create_i2c_client(adapter, "pca9548", 0x75, i2c_mux_props); + + // P1 SFP0 + mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 7), "24c02", 0x50, NULL); + + // P2 SFP1 + mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 6), "24c02", 0x50, NULL); + + mqnic->mod_i2c_client_count = 2; + + break; + } + + // EEPROM I2C bus switch (mqnic->board_id) { case MQNIC_BOARD_ID_EXANIC_X10: case MQNIC_BOARD_ID_EXANIC_X25: @@ -182,7 +416,16 @@ void mqnic_remove_i2c(struct mqnic_dev *mqnic) { int k; - // eeprom i2c interface + // unregister I2C clients + for (k = 0; k < ARRAY_SIZE(mqnic->mod_i2c_client); k++) + { + if (mqnic->mod_i2c_client[k]) + { + i2c_unregister_device(mqnic->mod_i2c_client[k]); + mqnic->mod_i2c_client[k] = NULL; + } + } + if (mqnic->eeprom_i2c_client) { i2c_unregister_device(mqnic->eeprom_i2c_client);