Загрузка данных


/**
 * 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;
}