mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
sfp: read the EEPROM in blocks instead of a byte at a time
The I2C controller transfers up to sixteen bytes per transaction and page_impl.c already used that for sfp_send_data(), while sfp_read_reg() asked for one byte and every caller looped. Reading a module therefore cost one address phase per byte: 87 transactions when a module is inserted, 52 for the sfp command, 36 for the vendor block in status.json. sfp_read_block() replaces sfp_read_reg() and the callers that already wanted a run of registers ask for it once: the vendor fields as three 16 byte pages, the diagnostics as one transfer, rate and encoding together. That drops the three paths above to 8, 6 and 3 transactions, and sfp_send_data() loses its copy of the transfer. The vendor loops now run over 16..63 rather than 20..59 so the page base is a multiple of sixteen and the index into the buffer is a single AND. The four extra bytes at each end are read and discarded. The diagnostics read asks for 16 bytes rather than the 15 it uses, because 16 is a width the shipped firmware already exercises and 15 is not. The device address, the bus selection and the start bit go into the control register in one write now that the memory address is written first, so a transfer touches that register once instead of three times. The register reads take their result from the SFRs directly rather than through the sfr_data mirror. The result is a bool and the destination is sfp_buf, so a caller that cares about a failed transfer looks at the return value instead of a flag. Every caller gives up on the first failed read rather than carrying a flag to the end, which is why the module read moved out of handle_sfp into a function of its own. A module whose read fails is left marked as absent, so the next poll retries it instead of configuring the SerDes from bytes that never arrived. BANK1 -194 bytes, BANK2 +382, common segment +44, xdata +15 for the buffer, and one byte more of internal RAM free than before the series. Built for all 25 machine definitions on sdcc 4.5.0; the tightest common segment is 98 bytes free on SWTG024AS_V2_0, against 54 before this series.
This commit is contained in:
+38
-24
@@ -129,39 +129,53 @@ void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) __banked{
|
||||
|
||||
|
||||
/*
|
||||
* Read a register of the EEPROM via I2C
|
||||
* Read up to 16 consecutive registers of the EEPROM via I2C into sfp_buf
|
||||
*/
|
||||
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg) __banked
|
||||
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
|
||||
{
|
||||
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
|
||||
reg &= 0x7f;
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x51 >> 5, (0x51 << 3) & 0xff);
|
||||
} else {
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x50 >> 5, (0x50 << 3) & 0xff);
|
||||
}
|
||||
uint8_t dev;
|
||||
uint8_t val;
|
||||
|
||||
reg_read_m(RTL837X_REG_I2C_CTRL);
|
||||
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2);
|
||||
reg_write_m(RTL837X_REG_I2C_CTRL);
|
||||
len--;
|
||||
if (len > 15)
|
||||
return false;
|
||||
|
||||
dev = (reg & 0x80) ? 0x51 : 0x50; // 0x51 holds the diagnostics, 0x50 the module data
|
||||
reg &= 0x7f;
|
||||
|
||||
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
|
||||
|
||||
// Execute I2C Read
|
||||
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
|
||||
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
|
||||
(dev >> 5) | i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5
|
||||
| i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2,
|
||||
((dev << 3) & 0xff) | 0x1);
|
||||
|
||||
// Wait for execution to finish
|
||||
do {
|
||||
reg_read_m(RTL837X_REG_I2C_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
reg_read(RTL837X_REG_I2C_CTRL);
|
||||
} while (SFR_DATA_0 & 0x1);
|
||||
|
||||
/* Bit 1 is the controller's own failure indication, which the vendor SDK
|
||||
* looks at and this did not. Without it an unacknowledged address comes
|
||||
* back as an ordinary byte and the caller cannot tell it from data. */
|
||||
if (sfr_data[3] & 0x2) {
|
||||
sfp_i2c_fail = 1;
|
||||
return 0xff;
|
||||
if (SFR_DATA_0 & 0x2)
|
||||
return false;
|
||||
|
||||
for (uint8_t i = 0; i <= len; i++) {
|
||||
switch (i & 0x3) {
|
||||
case 0:
|
||||
reg_read(RTL837X_REG_I2C_OUT + i);
|
||||
val = SFR_DATA_0;
|
||||
break;
|
||||
case 1:
|
||||
val = SFR_DATA_8;
|
||||
break;
|
||||
case 2:
|
||||
val = SFR_DATA_16;
|
||||
break;
|
||||
default:
|
||||
val = SFR_DATA_24;
|
||||
break;
|
||||
}
|
||||
sfp_buf[i] = val;
|
||||
}
|
||||
|
||||
reg_read_m(RTL837X_REG_I2C_OUT);
|
||||
return sfr_data[3];
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user