/**
* sysconfig_lpi2c_direct_pio_burst_write - Прямая монолитная PIO прокачка битстрима
* @lpi2c_imx: Указатель на приватную структуру контроллера LPI2C процессора i.MX95
* @buf: Указатель на буфер с побайтово инвертированной прошивкой (clean_reverse)
* @len: Полная длина файла на диске (выровненная до кратности 4 байтам)
*
* Функция осуществляет беспрерывное наполнение Tx FIFO в обход подсистемы прерываний
* и DMA ядра Linux. Защищает от BSE Timeout на стороне Lattice Nexus.
*/
int sysconfig_lpi2c_direct_pio_burst_write(struct lpi2c_imx_struct *lpi2c_imx,
const u8 *buf, size_t len)
{
size_t bytes_sent = 0;
u32 txcnt;
u32 msr;
unsigned long timeout = jiffies + msecs_to_jiffies(2000); // 2 секунды общего таймаута
if (!lpi2c_imx || !buf || len == 0)
return -EINVAL;
printk("sysCONFIG: Starting direct PIO burst upload of %zu bytes...\n", len);
/*
* Основной жесткий цикл процессора. Крутится до тех пор,
* пока все байты прошивки не будут физически записаны в регистр MTDR.
*/
while (bytes_sent < len) {
/* Читаем текущее количество слов во внутреннем Tx FIFO контроллера (макс 64) */
txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
/* Проверяем аппаратные флаги ошибок на шине (например, NACK от ПЛИС) */
msr = readl(lpi2c_imx->base + LPI2C_MSR);
if (msr & MSR_NDF) {
printk(KERN_ERR "sysCONFIG Direct PIO: NACK detected from FPGA at byte %zu!\n", bytes_sent);
return -EIO;
}
/*
* Если в 64-байтовом FIFO освободилось место (заполнено меньше чем на 56 байт),
* процессор мгновенно заталкивает туда очередную порцию данных.
*/
if (txcnt < 56) {
/*
* Младшие 8 бит — байт прошивки. Старшие биты 8-10 равны 0 (TRAN_DATA),
* что приказывает контроллеру i.MX95 просто выдать этот байт в линию SDA.
*/
writel(buf[bytes_sent], lpi2c_imx->base + LPI2C_MTDR);
bytes_sent++;
} else {
/*
* Если FIFO заполнено, даем аппаратную микропаузу в 5 микросекунд,
* чтобы I2C-автомат успел прожевать байты, не нагружая шину процессора.
*/
udelay(5);
}
/* Защита от вечного застревания, если шина I2C физически заклинит */
if (time_after(jiffies, timeout)) {
printk(KERN_ERR "sysCONFIG Direct PIO: Hardware upload timeout reached!\n");
return -ETIMEDOUT;
}
}
printk("sysCONFIG: Direct PIO burst stream successfully pushed to FIFO. Waiting for hardware empty...\n");
/*
* Финальная фаза: Ждем, пока аппаратное FIFO полностью опустеет в линию,
* перед тем как вернуть управление, чтобы закрывающий STOP-бит не срезал хвост прошивки.
*/
timeout = jiffies + msecs_to_jiffies(500);
do {
txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
if (txcnt == 0)
break;
udelay(10);
} while (time_before(jiffies, timeout));
printk("sysCONFIG: Direct PIO burst complete. Tx FIFO is clear.\n");
return 0;
}