Загрузка данных
static int sysconfig_i2c_bitstream_burst_init(struct sysconfig_priv *priv)
{
const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
struct i2c_client *client = to_i2c_client(priv->dev);
int ret;
/*
* Инициализируем сессию. Передаем команду начала burst-записи.
* Здесь флаг I2C_M_NOSTART НЕ используется, так как нам НАДО
* передать адрес устройства и сгенерировать START.
*/
ret = i2c_master_send(client, lsc_bitstream_burst, sizeof(lsc_bitstream_burst));
if (ret < 0) {
dev_err(priv->dev, "Burst init failed: %d\n", ret);
return ret;
}
return (ret == sizeof(lsc_bitstream_burst)) ? 0 : -EIO;
}
static int sysconfig_i2c_bitstream_burst_write(struct sysconfig_priv *priv, const char *buf, size_t len)
{
struct i2c_client *client = to_i2c_client(priv->dev);
struct i2c_msg msg;
size_t offset = 0;
int ret;
if (len == 0)
return 0;
printk("%s(%d) len=%ld\n",__FUNCTION__,__LINE__,len);
/*
* Цикл гарантирует, что если придет блок больше 4096 байт,
* он будет аккуратно разбит на максимальные страницы DMA (4КБ).
* Флаг I2C_M_NOSTART на каждом шаге удерживает шину i.MX95 от
* выдачи STOP/START-битов, сохраняя монолитность потока.
*/
while (offset < len) {
size_t chunk_size = min((size_t)4096, len - offset);
msg.addr = client->addr;
msg.flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
msg.len = chunk_size;
msg.buf = (u8 *)(buf + offset);
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret < 0) {
dev_err(priv->dev, "I2C continuous burst write failed at offset %zu: %d\n", offset, ret);
return ret;
}
if (ret != 1) {
dev_err(priv->dev, "I2C continuous burst write incomplete at offset %zu\n", offset);
return -EIO;
}
offset += chunk_size;
}
printk("%s(%d) OK\n",__FUNCTION__,__LINE__);
return 0;
}
static int sysconfig_i2c_bitstream_burst_complete(struct sysconfig_priv *priv)
{
printk("%s(%d) skipping JTAG bypass clocks for I2C\n",__FUNCTION__,__LINE__);
usleep_range(5000, 10000);
return 0;
}
Логи:
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: fpga_csi_bridge 2-0040: Loading FPGA bitstream file: jtag_stream_dump.bin ...
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: fpga_manager fpga0: writing jtag_stream_dump.bin to Lattice sysCONFIG FPGA Manager
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_init(395)
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_lsc_refresh(159) cmd=0x79 0x0 0x0 0x0 ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_activation_key(109) cmd=0xA4 0xC6 0xF4 0x8A ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_init(403) ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_read_idcode(70)
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_read_idcode(74) 0x1 0xF 0x10 0x43 ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_enable(217) cmd=0xC6 0x0 0x0 0x0 ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_init(258) ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_erase(239) cmd=0xE 0x0 0x0 0x0 ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_erase(244) ret=0 status=0x40114800E0044B5
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_init(418) ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_lsc_init_addr(269) cmd=0x46 0x0 0x0 0x0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_init(426) ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_i2c_bitstream_burst_init(246) cmd=0x7A 0x0 0x0 0x0 ret=4
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_init(435) ret=0
Oct 8 07:31:12 imx95-19x19-lpddr5-evk kernel: sysconfig_i2c_bitstream_burst_write(261) len=808328
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_i2c_bitstream_burst_write(289) OK
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_i2c_bitstream_burst_complete(411) skipping JTAG bypass clocks for I2C
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_complete(456) ret=0
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_finish(314) done_gpio=0000000000000000
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_finish(339) ret=0 status=0x40105800E000000
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_finish(341) [NEXUS HACK] Sending ISC_DISABLE before checking status done
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_disable(298) cmd=0x26 0x0 0x0 0x0
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_finish(347) Try use timeout for status done
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_isc_finish(351) ret=0 status=0x401058000000000
Oct 8 07:31:32 imx95-19x19-lpddr5-evk kernel: sysconfig_ops_write_complete(466) ret=-14