Refactor: Rename NanoKVM to BatchuKVM and update server URL
This commit is contained in:
BIN
tools/nanokvm_update_edid/E21_NanoKVM.bin
Normal file
BIN
tools/nanokvm_update_edid/E21_NanoKVM.bin
Normal file
Binary file not shown.
22
tools/nanokvm_update_edid/Makefile
Normal file
22
tools/nanokvm_update_edid/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# CROSS_COMPILE = aarch64-none-linux-gnu-
|
||||
# CROSS_COMPILE = riscv64-unknown-linux-gnu-
|
||||
CROSS_COMPILE = riscv64-unknown-linux-musl-
|
||||
# CROSS_COMPILE = riscv64-unknown-elf-
|
||||
|
||||
CFLAGS += -I/usr/local/RISC-V-toolchain/riscv64-linux-musl-x86_64/sysroot/usr/include
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
|
||||
SRC = nanokvm_update_edid.c
|
||||
|
||||
TARGET = nanokvm_update_edid
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(SRC)
|
||||
$(CC) -march=rv64gc -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
BIN
tools/nanokvm_update_edid/nanokvm_update_edid
Normal file
BIN
tools/nanokvm_update_edid/nanokvm_update_edid
Normal file
Binary file not shown.
749
tools/nanokvm_update_edid/nanokvm_update_edid.c
Normal file
749
tools/nanokvm_update_edid/nanokvm_update_edid.c
Normal file
@@ -0,0 +1,749 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "nanokvm_update_edid.h"
|
||||
|
||||
|
||||
int client;
|
||||
// old offset set to 0xff first
|
||||
static uint8_t old_offset = 0xff;
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
int get_edid_from_file(const char *filename, uint8_t *edid_data, uint16_t *edid_size) {
|
||||
FILE *file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
perror("Failed to open EDID file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*edid_size = fread(edid_data, 1, EDID_BUFFER_SIZE, file);
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_edid(uint8_t *edid_data, uint16_t edid_size)
|
||||
{
|
||||
uint16_t i;
|
||||
// Check if the EDID data length is valid
|
||||
if (edid_size != EDID_BUFFER_SIZE) {
|
||||
fprintf(stderr, "EDID data length is not %d bytes\n", EDID_BUFFER_SIZE);
|
||||
return -1; // EDID data length is not enough
|
||||
}
|
||||
|
||||
// Check EDID header
|
||||
if (edid_data[0] != 0x00 || edid_data[1] != 0xFF ||
|
||||
edid_data[2] != 0xFF || edid_data[3] != 0xFF ||
|
||||
edid_data[4] != 0xFF || edid_data[5] != 0xFF ||
|
||||
edid_data[6] != 0xFF || edid_data[7] != 0x00) {
|
||||
fprintf(stderr, "EDID header is invalid\n");
|
||||
return -1; // EDID header is invalid
|
||||
}
|
||||
|
||||
// First 128 Bytes checksum
|
||||
uint8_t checksum1 = 0;
|
||||
for (i = 0; i < 127; i++) {
|
||||
checksum1 += edid_data[i];
|
||||
}
|
||||
checksum1 = 0x100 - checksum1; // Reverse
|
||||
if (checksum1 != edid_data[127]) {
|
||||
// Checksum for first 128 bytes is incorrect
|
||||
fprintf(stderr, "Checksum for first 128 bytes is incorrect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Second 128 Bytes checksum
|
||||
uint8_t checksum2 = 0;
|
||||
for (i = 128; i < 255; i++) {
|
||||
checksum2 += edid_data[i];
|
||||
}
|
||||
checksum2 = 0x100 - checksum2; // Reverse
|
||||
if (checksum2 != edid_data[255]) {
|
||||
// Checksum for second 128 bytes is incorrect
|
||||
fprintf(stderr, "Checksum for second 128 bytes is incorrect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0; // EDID is valid
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
void NanoKVM_PCIe_HDMI_Reset(void)
|
||||
{
|
||||
system("echo 0 > /sys/class/gpio/gpio451/value");
|
||||
usleep(100000);
|
||||
system("echo 1 > /sys/class/gpio/gpio451/value");
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
// I2C write function
|
||||
int i2c_write_byte(uint8_t offset, uint8_t reg, uint8_t data)
|
||||
{
|
||||
// reg buffer
|
||||
uint8_t reg_buf[2] = {0};
|
||||
|
||||
// if offset is changed, write it first
|
||||
if (offset != old_offset) {
|
||||
old_offset = offset;
|
||||
reg_buf[0] = LT6911_REG_OFFSET; // Set the offset register
|
||||
reg_buf[1] = offset; // Set the register to read
|
||||
if (write(client, reg_buf, 2) != 2) {
|
||||
perror("Failed to write offset to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// write the data to the i2c bus
|
||||
reg_buf[0] = reg; // Set the register to write
|
||||
reg_buf[1] = data; // Set the data to write
|
||||
if (write(client, reg_buf, 2) != 2) {
|
||||
perror("Failed to write to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_write_bytes(uint8_t offset, uint8_t reg, const uint8_t *data, size_t len)
|
||||
{
|
||||
// check len
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "Data length must be greater than 0.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reg buffer
|
||||
uint8_t reg_buf[1 + len];
|
||||
|
||||
// if offset is changed, write it first
|
||||
if (offset != old_offset) {
|
||||
old_offset = offset;
|
||||
reg_buf[0] = LT6911_REG_OFFSET; // Set the offset register
|
||||
reg_buf[1] = offset; // Set the register to read
|
||||
if (write(client, reg_buf, 2) != 2) {
|
||||
perror("Failed to write offset to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// write the data to the i2c bus
|
||||
reg_buf[0] = reg;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
reg_buf[i + 1] = data[i];
|
||||
}
|
||||
|
||||
// write to the I2C bus
|
||||
if (write(client, reg_buf, 1 + len) != 1 + len) {
|
||||
perror("Failed to write to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// I2C read function
|
||||
int i2c_read_byte(uint8_t offset, uint8_t reg, uint8_t *data)
|
||||
{
|
||||
// reg buffer
|
||||
uint8_t reg_buf[2] = {0};
|
||||
|
||||
// if offset is changed, write it first
|
||||
if (offset != old_offset) {
|
||||
old_offset = offset;
|
||||
reg_buf[0] = LT6911_REG_OFFSET; // Set the offset register
|
||||
reg_buf[1] = offset; // Set the register to read
|
||||
if (write(client, reg_buf, 2) != 2) {
|
||||
perror("Failed to write offset to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// write the register address to read
|
||||
reg_buf[0] = reg; // Set the register to read
|
||||
if (write(client, reg_buf, 1) != 1) {
|
||||
perror("Failed to write register address to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// read the data from the i2c bus
|
||||
if (read(client, data, 1) != 1 ) {
|
||||
perror("Failed to read from the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_read_bytes(uint8_t offset, uint8_t reg, uint8_t *data, size_t len)
|
||||
{
|
||||
// 检查数据长度
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "Data length must be greater than 0.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t reg_buf[2]; // 创建寄存器缓冲区
|
||||
|
||||
// 如果偏移量改变,先写入偏移量
|
||||
if (offset != old_offset) {
|
||||
old_offset = offset;
|
||||
reg_buf[0] = LT6911_REG_OFFSET; // 设置偏移寄存器
|
||||
reg_buf[1] = offset; // 设置偏移值
|
||||
if (write(client, reg_buf, 2) != 2) {
|
||||
perror("Failed to write offset to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 写入要读取的寄存器地址
|
||||
reg_buf[0] = reg; // 设置要读取的寄存器
|
||||
if (write(client, reg_buf, 1) != 1) {
|
||||
perror("Failed to write register address to the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 从 I2C 总线读取数据
|
||||
if (read(client, data, len) != len) {
|
||||
perror("Failed to read from the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
int lt6911_enable(void) {
|
||||
// Enable the LT6911UXC by writing to the appropriate register
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xEE, 0x01) != 0) {
|
||||
fprintf(stderr, "Failed to enable LT6911UXC\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lt6911_disable(void) {
|
||||
// Disable the LT6911UXC by writing to the appropriate register
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xEE, 0x00) != 0) {
|
||||
fprintf(stderr, "Failed to disable LT6911UXC\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
int lt6911uxc_edid_write(uint8_t *edid_data, uint16_t edid_size)
|
||||
{
|
||||
uint8_t i;
|
||||
int ret;
|
||||
uint8_t chip_data[16] = {0};
|
||||
uint8_t wr_count = edid_size / LT6911UXC_WR_SIZE + 1;
|
||||
uint8_t version_str[32] = {0};
|
||||
|
||||
fprintf(stdout, "Writing EDID....\n");
|
||||
|
||||
// Start
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0xDF) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x00) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x59, 0x51) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x10) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x00) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x21) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x84) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5B, 0x01) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x81) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
// Waiting for erasure
|
||||
usleep(500000);
|
||||
|
||||
if (i2c_read_byte(LT6911_SYS3_OFFSET, 0x08, chip_data) != 0) return -1;
|
||||
if (chip_data[0] != 0xEE) {
|
||||
fprintf(stderr, "Unsupported chip version\n");
|
||||
return -1;
|
||||
}
|
||||
if (i2c_write_byte(LT6911_SYS3_OFFSET, 0x08, 0xAE) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS3_OFFSET, 0x08, 0xEE) != 0) return -1;
|
||||
// Write
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x84) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x84) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
for (i = 0; i < wr_count; i++) {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0xDF) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x20) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x00) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x21) != 0) return -1;
|
||||
if (i != wr_count-1) {
|
||||
if (i2c_write_bytes(LT6911_SYS_OFFSET, 0x59, edid_data+(LT6911UXC_WR_SIZE*i), LT6911UXC_WR_SIZE) != 0) return -1;
|
||||
} else {
|
||||
if (i2c_write_bytes(LT6911_SYS_OFFSET, 0x59, version_str, LT6911UXC_WR_SIZE) != 0) return -1;
|
||||
}
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5B, 0x01) != 0) return -1;
|
||||
if (i != wr_count-1) {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00+(LT6911UXC_WR_SIZE*i)) != 0) return -1;
|
||||
} else {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x81) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00) != 0) return -1;
|
||||
}
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0xC0) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x90) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
if (i != wr_count-1) {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x84) != 0) return -1;
|
||||
} else {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x88) != 0) return -1;
|
||||
}
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
}
|
||||
if (i2c_read_byte(LT6911_SYS3_OFFSET, 0x08, chip_data) != 0) return -1;
|
||||
if (chip_data[0] != 0xEE) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS3_OFFSET, 0x08, 0xAE) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS3_OFFSET, 0x08, 0xEE) != 0) return -1;
|
||||
|
||||
fprintf(stdout, "EDID write completed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lt6911uxc_edid_read(uint8_t *edid_data, uint16_t edid_size)
|
||||
{
|
||||
uint8_t i;
|
||||
int ret;
|
||||
uint8_t chip_data[16] = {0};
|
||||
uint8_t wr_count = edid_size / LT6911UXC_WR_SIZE;
|
||||
|
||||
// Read EDID data from LT6911UXC
|
||||
fprintf(stdout, "Reading EDID...\n");
|
||||
// Read
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x84) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
for (i = 0; i < wr_count; i++) {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0x5F) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0xA0) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5B, 0x01) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00+(LT6911UXC_WR_SIZE*i)) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x90) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x21) != 0) return -1;
|
||||
if (i2c_read_bytes(LT6911_SYS_OFFSET, 0x5F, edid_data+(LT6911UXC_WR_SIZE*i), LT6911UXC_WR_SIZE) != 0) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lt6911c_edid_write(uint8_t *edid_data, uint16_t edid_size)
|
||||
{
|
||||
uint8_t i;
|
||||
int ret;
|
||||
uint8_t chip_data[16] = {0};
|
||||
uint8_t wr_count = edid_size / LT6911C_WR_SIZE;
|
||||
uint8_t version_str[32] = {0};
|
||||
|
||||
fprintf(stdout, "Writing EDID....\n");
|
||||
|
||||
// Start
|
||||
lt6911_enable();
|
||||
if (i2c_read_bytes(LT6911_SYS4_OFFSET, 0x00, chip_data, 2) != 0) return -1;
|
||||
if (chip_data[0] != 0x16 || chip_data[1] != 0x05) {
|
||||
fprintf(stderr, "Unsupported chip version\n");
|
||||
return -1;
|
||||
}
|
||||
lt6911_disable();
|
||||
|
||||
usleep(100000);
|
||||
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_read_bytes(LT6911_SYS4_OFFSET, 0x00, chip_data, 2) != 0) return -1;
|
||||
if (chip_data[0] != 0x16 || chip_data[1] != 0x05) {
|
||||
fprintf(stderr, "Unsupported chip version\n");
|
||||
return -1;
|
||||
}
|
||||
lt6911_disable();
|
||||
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0xC0) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x00) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x59, 0x51) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x92) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x86) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5B, 0x01) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x83) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
|
||||
// waiting to clean
|
||||
usleep(500000);
|
||||
if (i2c_read_byte(LT6911_SYS2_OFFSET, 0x02, chip_data) != 0) return -1;
|
||||
if (chip_data[0] != 0xFF) {
|
||||
fprintf(stderr, "Clean Error\n");
|
||||
return -1;
|
||||
}
|
||||
if (i2c_write_byte(LT6911_SYS2_OFFSET, 0x02, 0xDF) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS2_OFFSET, 0x02, 0xFF) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x86) != 0) return -1;
|
||||
|
||||
for (i = 0; i < wr_count; i++) {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x86) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0xEF) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0xA2) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x01) != 0) return -1;
|
||||
if (i2c_write_bytes(LT6911_SYS_OFFSET, 0x59, edid_data+(LT6911C_WR_SIZE*i), LT6911C_WR_SIZE) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5B, 0x01) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00+(LT6911C_WR_SIZE*i)) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0xE0) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x92) != 0) return -1;
|
||||
}
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x8A) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_read_byte(LT6911_SYS2_OFFSET, 0x02, chip_data) != 0) return -1;
|
||||
if (chip_data[0] != 0xFF) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS2_OFFSET, 0x02, 0xDF) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS2_OFFSET, 0x02, 0xFF) != 0) return -1;
|
||||
|
||||
fprintf(stdout, "EDID write completed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lt6911c_edid_read(uint8_t *edid_data, uint16_t edid_size)
|
||||
{
|
||||
uint8_t i;
|
||||
int ret;
|
||||
uint8_t chip_data[16] = {0};
|
||||
uint8_t wr_count = edid_size / LT6911C_WR_SIZE;
|
||||
|
||||
// Read EDID data from LT6911UXC
|
||||
fprintf(stdout, "Reading EDID...\n");
|
||||
// Read
|
||||
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0xFF, 0x80) != 0) return -1;
|
||||
lt6911_enable();
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x86) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
|
||||
for (i = 0; i < wr_count; i++) {
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5E, 0x6F) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0xA2) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5B, 0x01) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5C, 0x80) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5D, 0x00+(LT6911C_WR_SIZE*i)) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x92) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x5A, 0x82) != 0) return -1;
|
||||
if (i2c_write_byte(LT6911_SYS_OFFSET, 0x58, 0x01) != 0) return -1;
|
||||
if (i2c_read_bytes(LT6911_SYS_OFFSET, 0x5F, edid_data+(LT6911C_WR_SIZE*i), LT6911C_WR_SIZE) != 0) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
int lt6911_edid_config(chip_version_t chip_version, uint8_t *edid_data, uint16_t edid_size)
|
||||
{
|
||||
if (chip_version == CHIP_UNKNOWN)
|
||||
{
|
||||
fprintf(stderr, "Unknown chip version\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// open i2c device
|
||||
if ((client = open(I2C_DEVICE, O_RDWR)) < 0) {
|
||||
perror("Failed to open the i2c bus");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// // set the lt6911uxc address
|
||||
if (ioctl(client, I2C_SLAVE, I2C_ADDRESS) < 0) {
|
||||
perror("Failed to acquire bus access and/or talk to slave");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// edid write
|
||||
if (chip_version == CHIP_LT6911UXC) {
|
||||
if (lt6911uxc_edid_write(edid_data, edid_size) != 0) {
|
||||
fprintf(stderr, "Failed to write EDID data to LT6911UXC\n");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
} else if (chip_version == CHIP_LT6911C) {
|
||||
if (lt6911c_edid_write(edid_data, edid_size) != 0) {
|
||||
fprintf(stderr, "Failed to write EDID data to LT6911C\n");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown chip version\n");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
// sleep 1s
|
||||
sleep(1);
|
||||
|
||||
// read edid data back
|
||||
uint8_t edid_read_data[EDID_BUFFER_SIZE] = {0};
|
||||
if (chip_version == CHIP_LT6911UXC) {
|
||||
if (lt6911uxc_edid_read(edid_read_data, EDID_BUFFER_SIZE) != 0) {
|
||||
fprintf(stderr, "Failed to read EDID data from LT6911UXC\n");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
} else if (chip_version == CHIP_LT6911C) {
|
||||
if (lt6911c_edid_read(edid_read_data, EDID_BUFFER_SIZE) != 0) {
|
||||
fprintf(stderr, "Failed to read EDID data from LT6911C\n");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown chip version\n");
|
||||
close(client);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check if the read data matches the written data
|
||||
if (memcmp(edid_data, edid_read_data, EDID_BUFFER_SIZE) != 0) {
|
||||
fprintf(stderr, "EDID data mismatch after write/read cycle\n");
|
||||
// print edid with 16*16 hex format
|
||||
fprintf(stderr, "Written EDID data:\n");
|
||||
for (int i = 0; i < EDID_BUFFER_SIZE; i++) {
|
||||
fprintf(stderr, "%02X ", edid_data[i]);
|
||||
if ((i + 1) % 16 == 0) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\nRead EDID data:\n");
|
||||
for (int i = 0; i < EDID_BUFFER_SIZE; i++) {
|
||||
fprintf(stderr, "%02X ", edid_read_data[i]);
|
||||
if ((i + 1) % 16 == 0) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
close(client);
|
||||
return -1;
|
||||
} else {
|
||||
fprintf(stdout, "EDID data verified successfully\n");
|
||||
}
|
||||
|
||||
// close client
|
||||
close(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
void print_warning(product_version_t product_version) {
|
||||
printf("\n=========================================================\n");
|
||||
printf("Incorrect EDID may cause issues such as \n");
|
||||
printf("inability to display images, please modify with caution\n");
|
||||
printf("=========================================================\n\n");
|
||||
|
||||
if (product_version == PRODUCT_CUBE_A || product_version == PRODUCT_CUBE_B) {
|
||||
printf("\n==========================================================\n");
|
||||
printf("⚠️ WARNING: Hardware version detected as Cube/Lite!\n");
|
||||
printf("==========================================================\n");
|
||||
printf("After flashing, you MUST manually power cycle the device!\n");
|
||||
printf("Please ensure you can physically disconnect its power,\n");
|
||||
printf("NOT just remotely reboot it!!\n");
|
||||
printf("==========================================================\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
void print_success(product_version_t product_version) {
|
||||
printf("\n=========================================================\n");
|
||||
printf("✅ EDID update successful!\n");
|
||||
if (product_version == PRODUCT_CUBE_A || product_version == PRODUCT_CUBE_B) {
|
||||
printf("Please manually power cycle the device to apply changes.\n");
|
||||
}
|
||||
printf("=========================================================\n\n");
|
||||
}
|
||||
|
||||
int get_user_confirmation() {
|
||||
char input[256];
|
||||
printf("Do you want to continue? (Y/N): \n");
|
||||
|
||||
while (1) {
|
||||
|
||||
if (fgets(input, sizeof(input), stdin) == NULL) {
|
||||
printf("\nInput error. Exiting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 去除换行符
|
||||
input[strcspn(input, "\n")] = '\0';
|
||||
|
||||
if (strlen(input) == 0) {
|
||||
continue; // 空输入,重新提示
|
||||
}
|
||||
|
||||
// 转换为小写方便比较
|
||||
char choice = tolower(input[0]);
|
||||
|
||||
if (choice == 'y') {
|
||||
return 1;
|
||||
} else if (choice == 'n') {
|
||||
return 0;
|
||||
} else {
|
||||
printf("Invalid input. Please enter Y or N.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================================================
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
uint8_t counter = 0;
|
||||
|
||||
// Check version
|
||||
chip_version_t chip_version = CHIP_UNKNOWN;
|
||||
product_version_t product_version = PRODUCT_UNKNOWN;
|
||||
char chip_version_str[32] = {0};
|
||||
char product_version_str[32] = {0};
|
||||
|
||||
FILE *file = fopen(VERSION_PATH, "r");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Please upgrade to the latest system\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fgets(chip_version_str, sizeof(chip_version_str), file) == NULL) {
|
||||
fprintf(stderr, "Failed to read chip version\n");
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
file = fopen(PRODUCT_PATH, "r");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Please upgrade to the latest system\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fgets(product_version_str, sizeof(product_version_str), file) == NULL) {
|
||||
fprintf(stderr, "Failed to read product version\n");
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
chip_version_str[strcspn(chip_version_str, "\n")] = '\0';
|
||||
product_version_str[strcspn(product_version_str, "\n")] = '\0';
|
||||
|
||||
if (strcmp(chip_version_str, "c") == 0) {
|
||||
fprintf(stdout, "Chip Version: LT6911C\n");
|
||||
chip_version = CHIP_LT6911C;
|
||||
} else if (strcmp(chip_version_str, "ux") == 0) {
|
||||
fprintf(stdout, "Chip Version: LT6911UXC\n");
|
||||
chip_version = CHIP_LT6911UXC;
|
||||
} else if (strcmp(chip_version_str, "ue") == 0) {
|
||||
fprintf(stderr, "Chip Version Error: UE version's edid can't be updated\n");
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, "Chip Version Error: Unknown version\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(product_version_str, "alpha") == 0) {
|
||||
fprintf(stdout, "Product Version: CUBE_A\n");
|
||||
product_version = PRODUCT_CUBE_A;
|
||||
} else if (strcmp(product_version_str, "beta") == 0) {
|
||||
fprintf(stdout, "Product Version: CUBE_B\n");
|
||||
product_version = PRODUCT_CUBE_B;
|
||||
} else if (strcmp(product_version_str, "pcie") == 0) {
|
||||
fprintf(stdout, "Product Version : PCIE_A\n");
|
||||
product_version = PRODUCT_PCIE_A;
|
||||
} else {
|
||||
fprintf(stderr, "Product Version Error: Unknown version\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_warning(product_version);
|
||||
if (product_version == PRODUCT_CUBE_A || product_version == PRODUCT_CUBE_B) {
|
||||
if (get_user_confirmation() == 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// check command line arguments
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Please enter the location of the EDID file using \"%s /path/to/edid.bin\"\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint16_t edid_size = 0;
|
||||
uint8_t edid_data[EDID_BUFFER_SIZE] = {0};
|
||||
if (get_edid_from_file(argv[1], edid_data, &edid_size) != 0) {
|
||||
fprintf(stderr, "Failed to read EDID data from file %s\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (check_edid(edid_data, edid_size) != 0) {
|
||||
fprintf(stderr, "EDID data is invalid\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fprintf(stdout, "EDID data loaded successfully from %s\n", argv[1]);
|
||||
|
||||
if (product_version == PRODUCT_PCIE_A) NanoKVM_PCIe_HDMI_Reset();
|
||||
|
||||
// configure lt6911 edid
|
||||
if (lt6911_edid_config(chip_version, edid_data, edid_size) != 0) {
|
||||
fprintf(stderr, "Failed to configure LT6911 EDID\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (product_version == PRODUCT_PCIE_A) NanoKVM_PCIe_HDMI_Reset();
|
||||
|
||||
print_success(product_version);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
41
tools/nanokvm_update_edid/nanokvm_update_edid.h
Normal file
41
tools/nanokvm_update_edid/nanokvm_update_edid.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef NANOKVM_UPDATE_EDID_H
|
||||
#define NANOKVM_UPDATE_EDID_H
|
||||
|
||||
#define I2C_DEVICE "/dev/i2c-4" // I2C 设备文件
|
||||
#define EDID_BUFFER_SIZE 256 // 最大支持的字节数
|
||||
|
||||
#define I2C_ADDRESS 0x2b // I2C 设备地址(根据实际设备调整)
|
||||
#define LT6911_REG_OFFSET 0xFF // LT6911UXC 寄存器偏移地址
|
||||
#define LT6911_SYS_OFFSET 0x80 // LT6911UXC 寄存器偏移地址
|
||||
#define LT6911_SYS2_OFFSET 0x90 // LT6911UXC 寄存器偏移地址
|
||||
#define LT6911_SYS3_OFFSET 0x81 // LT6911UXC 寄存器偏移地址
|
||||
#define LT6911_SYS4_OFFSET 0xA0 // LT6911UXC 寄存器偏移地址
|
||||
#define LT6911_CSI_INFO_OFFSET 0x85 // LT6911UXC CSI接口信息寄存器偏移地址
|
||||
#define LT6911_HDMI_INFO_OFFSET 0x86 // LT6911UXC HDMI信息寄存器偏移地址
|
||||
#define LT6911_CSI_TOTAL_OFFSET 0xD4 // LT6911UXC CSI总线统计信息
|
||||
#define LT6911_AUDIO_INFO_OFFSET 0xB0 // LT6911UXC 音频信息寄存器偏移地址
|
||||
#define LT6911C_HDMI_INFO_OFFSET 0xD2 // LT6911C HDMI信息寄存器偏移地址
|
||||
#define LT6911C_AUDIO_INFO_OFFSET 0xD1 // LT6911C 音频信息寄存器偏移地址
|
||||
#define LT6911C_CSI_INFO_OFFSET 0xC2 // LT6911C CSI信息寄存器偏移地址
|
||||
|
||||
#define EDID_BUFFER_SIZE 256 // 最大支持的字节数
|
||||
#define LT6911UXC_WR_SIZE 32 // LT6911UXC单次读写最大字节数
|
||||
#define LT6911C_WR_SIZE 16 // LT6911C单次读写最大字节数
|
||||
|
||||
#define VERSION_PATH "/etc/kvm/hdmi_version"
|
||||
#define PRODUCT_PATH "/etc/kvm/hw"
|
||||
|
||||
typedef enum {
|
||||
CHIP_LT6911UXC = 0,
|
||||
CHIP_LT6911C,
|
||||
CHIP_UNKNOWN
|
||||
} chip_version_t;
|
||||
|
||||
typedef enum {
|
||||
PRODUCT_CUBE_A = 0,
|
||||
PRODUCT_CUBE_B,
|
||||
PRODUCT_PCIE_A,
|
||||
PRODUCT_UNKNOWN,
|
||||
} product_version_t;
|
||||
|
||||
#endif // NANOKVM_UPDATE_EDID_H
|
||||
Reference in New Issue
Block a user