From 350dbdfe4b60557a2406d68ab748f1b4e0b1b248 Mon Sep 17 00:00:00 2001 From: BuGu <62454025+Z2Z-GuGu@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:51:48 +0800 Subject: [PATCH] Add NanoKVM EDID Update tool --- tools/nanokvm_update_edid/E21_NanoKVM.bin | Bin 0 -> 256 bytes tools/nanokvm_update_edid/Makefile | 22 + tools/nanokvm_update_edid/nanokvm_update_edid | Bin 0 -> 24240 bytes .../nanokvm_update_edid/nanokvm_update_edid.c | 749 ++++++++++++++++++ .../nanokvm_update_edid/nanokvm_update_edid.h | 41 + 5 files changed, 812 insertions(+) create mode 100644 tools/nanokvm_update_edid/E21_NanoKVM.bin create mode 100644 tools/nanokvm_update_edid/Makefile create mode 100755 tools/nanokvm_update_edid/nanokvm_update_edid create mode 100644 tools/nanokvm_update_edid/nanokvm_update_edid.c create mode 100644 tools/nanokvm_update_edid/nanokvm_update_edid.h diff --git a/tools/nanokvm_update_edid/E21_NanoKVM.bin b/tools/nanokvm_update_edid/E21_NanoKVM.bin new file mode 100644 index 0000000000000000000000000000000000000000..005cad48ffef12727d945e7835cd60df346cbbd5 GIT binary patch literal 256 zcmZSh4+ac=ER4pY3=9l%%8bkn2GSK;nW~GU0~V_b281m2X1I8uv4If@Fj+N76k6yy zMCiCO+~E-fY6EKh&)}Dsm+u|s%cTGUK#@NfB7YeyeB^=!86Zj&7{4+x3mUkw$cqRw g3ZydgFbFVU8qFxnP!xDUP9aYt6k!?AbZUTG0NVs90RR91 literal 0 HcmV?d00001 diff --git a/tools/nanokvm_update_edid/Makefile b/tools/nanokvm_update_edid/Makefile new file mode 100644 index 0000000..9b7b9ca --- /dev/null +++ b/tools/nanokvm_update_edid/Makefile @@ -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 \ No newline at end of file diff --git a/tools/nanokvm_update_edid/nanokvm_update_edid b/tools/nanokvm_update_edid/nanokvm_update_edid new file mode 100755 index 0000000000000000000000000000000000000000..8b2489ed51c72931ed65bfee671abce24b44a39c GIT binary patch literal 24240 zcmeHve|%KMx%X@~$r6wxuqsfs9Eb?EO*SAPpg;nI$Sn{=AllZuY<4%vYO=fRZou?P zNeG)2D+HQa)M^s}5pofz^%t}Xt-r7JhTdw`_f=U13tDBPQX`N}-tRL%cF!I{?e+8C zf9}W0CwtEM&humDnP;AvGv}OHQ!;;Un#sgeN@JfheszJsie!d=nK;S7p@>ak7W|H4 z8q36WI>$tQk>EzI;J-s0m^uy+WXvr2UXuAQ$ug+pweW%z@A?lyF5>%VlT^nR zgOBWazH+`P^{J!0WVRYlg{{VwUt1Tf$q#sf&XtoV76g3-<7EMc;5ZWh7s>0PIF7*o zF#KPN|BLZI82?mesNFTuZ6Vs!X6{#BdN^+5dR;9r@Q zFiOMmPi0c+LYycYP@TvI#xw{3@hIOR{SAlaE+6{5`-f|%d^o>>wQKBhb_g^mDl}in z4iPPtpJ?^vr}|JGC{g)IKiPonL3W`!P~FG|b4_(Q*4s1p7CyCh@JD}+Wv_bUm$&cV z@M-p)$4*|l=<%JotA85InQ^-BceaJozgT?NxKY14>&-db+ZDUKZtdWypZ)aGQJq=w z_O@L)Bft1juKgFSm*)Q4{kK;wb>#l=zH4&&K3;cW(SiqVx7b2C<1V}F(qSL1?1jqn zraj2f`pJFaJa_|eYU{#5%2RNGG!g%VZ!+LxCBDdjUkiLR{*8%jMsf}t=tlwTkDkH^ z(eE3WTAp@^M-4dnE72DjW;_>q0?R>GQk2 ztg_0DbGygu39(vtZO|PeVviTU0cX(fW%f$sQI@mT&k*0Z+)y z2u3so0SfD`@<4jPUKw!Ix>3AJ!uvx}<%At5o~d|BxM~-|DHf`v{D*LASCw)XiT*;d zjAE5a!*#fdXOySuaEiYwjnm=!I9;g2DF&)EMTe{SOnF5*Tpw4j)8T5YA^Jr+T=fmY zZ`9#5R;aXGhf}Opsal8YBZyyzQ=eApHXW`XZyI#Cer&o!htqhY(k30QpMTt=!}a4} zyAG!qsnSjzuAd+5)8YED?k^JC6TwX&yVpwk}U|6`R&J5KZ{m;vuc!#!Z4UygBojqTRZ@*!1+l#}7_jk=Zl) z%LbNr?e?C$DUbE!O?$YX0qIHiFr~wC=W(EBGxSyb8#!Ed-66NXOPev>zes~W9f|W`~F#>QI53@ z^(!(@jqYN@N#CAG-X*7cn#x`AOClDsOs+Gho4sCTell{5BvUye2d0H%U44Ivm%Fz@ zZoKJ53w!G*orNuQJ|og<>B@0_t2>jh^?EEo$<#og&dw^@%}+MPz&-Fj@O!0y#! z!@C*LJ;1Teov&9lp`6b&-#j;5LYA>S9qU^2X1v_Abz5e7Z{D!<-iz9s%8&J$!E;~> zmDODOTJQe0ZJDQf2@j9W8z#;~?W2~Xr;qnEf#$cCt|Cqa&elk`#SC7;Tf4h+oDIj* zlxAyYdz#Q4c?R}B9527VJrBBJ$pIw$T>Z~Mf8P1@=Lr4Jas8Z1=+6=QpX*2eKBfQn z(En1rd`LUB^;Umcs03|YJS6kj=qMY&{pPt?SKAZsk)3Wqd+y^FdlCNixWW$ZH6?sk zc}YiPPxFMxwwzNvPek(Ydmyqc`&3Wfh3UQK7aLoeN>9bPO&X7r0(k-Hey%W$5pSmrvT+RC+8f_+IOmukR5( zpXHCSt|L2)wY_Xb^T%6H>^Rntn>XdTGkFtVJJZp;E$6i}dz$m`duQ_#>(FD)+3>#}#vt@q4ezp1|1WF0<(O>SzOZC&Ug!>&SP`GRe3`kCb_)2BsuMxKe}O+3{jt#g)JXC1fBS+WlNw`X;EUc+(n z^3@wm9pkGO=vK0;}4^3El(Rn!`+Y0*9zUN3tJt9yCm!Z(M-2&Y}GSZT=NB+COcLCRzvTc{Z*Q1n2 z{wng6tRoMLyvrW6W)`7l3b*eN_*CE|OW{Yh3;dlu)UNwvIoE6x=<_=S^&wUM2L=A# z4zj^viMF*1bip2!UnhHHo4`H5^*Y-g5cs?uPd;p67+r>TN$4_^Z2N&p)Nw?a0qW-dnp<>tNq3@YTTec0SS~@SC?A=r;V0d? zT_QJ3THpbyb^7iU_=CI2-U@A7FVOXnlHxCS2t0o~#?oGzpPGXn1d{-doxl1iGN3AH6x< zX~Gi9hxWz=_4Qkcno2``mdc>~spTxn@JhUV!&c!>iZkbo;M}!U?|pl}6zD}A&~rhu zzuLM5KA!Nbr1kdxUEo6?UGJ5)Qv&~cdq1_v?q;d&T=prbJLBc6cUm(WbUxo16H;z& zPnBMFQsDJmdU)(ML?|=rPc39!)ty5&I9l2LZfY+$BK_h)#P~!nNbhFx@_Qja>F>T1 zLV5;Dll1qT;{v^Mr;2?`Rj+v`))m`H^FA7(X?#{A8lo%B@vWG#C8KMPimnt_m8@bF zN8gQg*`&9t9_2eCG(WNxW9peC0x=GuHBOfDaq^!XAzPYp z4}kkp+^5Z*(cFmW%m$*pyF|H0Z4-X^R;iQjv`T-DNPTzd`QmhEW4!#WU9ql~K6(ET zJ@_}#4$5z0zZG&zKxI2^)Y>V%eBQ4AhSunsGx72;MoODuthYTbbZthS?=x$rrt8H% zIS&{^qoppU#C|P!OuHxoHON+Kk#m4gX#CU70dn>V>Q^z|XgZ&1k+Xmg3D;@Ok@El= zN69;tRa!cP9M7IuSLg9mp3a>j?`iNX*U2iA^MD5oIyxT`^!s<{`-M-=0>((qs$aym z3hIoM@xDdQ0%#m9)alHT^MF?|is|ds@+%?b!`+GTK05M`BGRoVkIF*pJR@js-mM}X zRtWgYf*9||tH>3NMeXmz%j@|FsW)(L%$GJ2|Z_caN8j2xp& z&l#i38U@7&;!M^odZbU_al}2H&qwXO0)LCgz4MHJw{)LKv3Imjj`$^z)}HjV=o%Rp z9i&Bv_sKCoyff9i%A|iJ$5D7!VjS%nEIlUL_qiw~jiU)aine_w(0<3!=$gm=JL70F z`t~!9Mi1^y>G{#VkA&t2Fpk<#CY{ekXMQO1cA*9IHaI9p{lR=39RW}3%1n4(^vDN- zYY2H*((|JBV*>v>wCJTBd0*hK>&MaPn)d{H8un+fzx11EpB(pZmgDF-eiJ<+NB`?d zPckM(?Q-;g+^AoU`*(Bw((|Kh-V*xv^Kmi7^D&AF&sSrpFDz*P;TY;o9YZ}UGQSx8 z8T(cT)+!$RctRwv;MB)ht+?#e$4z6O`-EoJSdkh@>z*PyCFWJ{#iDCkFJ34`o*M_MQWw+Z?WjeW+i3KdaNPrR#f_$A8ArFGb8cxD|cs<#G);q ziZb&v%!+9 zcoCVDoj#}fDtv*OAAf=RewKGddhh;rZ7U~FZ&F_PN?3C*`5&!9Ux7OZoQYNFuAHN<9Y3S=Ce}B;1pP;OmkYgSta~?& zUDw;1ncnvVR<xi8BrQo;R`g zm(Ox#oVRQ(&vLHI!T*PT$}vo?QeT1mLtGO|Ty`iaHGf6s$Z24l>MX*HHiss&}XP6nSRQT8lwA6`h=Jek6rPO8{O35dTYi+px5^HZ*QOEz3 z^fSEN&;k*m;N2g9YScc4~hu}&F>Rnn+Nomls}`>67BwOVMI z4Eo=h>B(1g?-SwD2lj~b*yB2_Q(%urze;Q8li|`ad!Y5SUaJpt;H1{oY92Zj<#|kK zD%%?_HSG}REql;TXOrzj_Xe_^)>(RxcRHEZxks0GM)6s$;qCkH9g(o8D|*vSDwbS> z_IU))3}N}F$s@QX%XH$1(TrcLI)lTZIHtqi9U}TD`p8U9Pji0VDz)D%pNSR0o)3ph zr*Bu5#{IjBaI>NRp>S!|ZdDV@T#{v@ng6-E=fc0YQUsdUuIMAzary`JwNqua%maNJ zY6p*Mq}p*?S-wvkIrr%~)aqa4`zX)-@I-J-6{{S0x|baPA`6gzU$}I`R*G6Q#*Exg zXCiutIEE1f_pZ3heF1eiirztE%LzHgo4WDjj>pcc(@)&*l#zN7x8EJ%(kr*-T>?*^ zl76DqvhG9u2$!>=2^;wpMaehB|*4wq)MtGKV^v^=eB+V%*=^e_C&LL(3@=$(o{1^wb3 zLx-ov?b1R%&4+iNw30dV=4h3GL@r|-a5+K_t;X%G3RP>Kpyu_3v@tHNqCVsfs&{8N zT{YfmatDaS<6Y^f@wf)E+0}06t--oltjh`?@@CrhwFA#7$LsC!*ebDXn zd0qdI!R@T}X@%Mh&4zccY|a`-Flejtdwl$7;-v95l%o!{;dJA_nl5P%{sxxjtE|Ke zU}T?AwOjK{aB3BG!4$g*IwQdxoyqWSY)GqcYgKsX3omd%lEbSN7VsJy^{Mx{G>6L- za0i1%%}IKCflR9m_-a#1mdtm19ThchZT^zUQ^${AdgE+i;AFnb6YPhe9PgcZyj9#0 z3XoL$F7*cM{C-~`1ZQzpd;Ho;cOdBTc~w4de_;xzuhw7V1|j7wMk#gj6git+(z<5;O2Jt_t z!8&fm%DS4GdMO?J)4y&K6`$vo{a=)!)={rH9d$u;wP3K$9VDfwVUUW-lLubysquvB zsR7}_{u*$2Y8_SX;P*7Rodc}3K9{GmUR&isxPq_{+?0LYQcjmO{rdHs&ddG&eeJQQ zS~RV^c=5t{3rnYI*Es^NRSx*4>`0mmUB*e>3$>kHSK+qJ#~YxdWVOG3`GtB`%$=kX z@v$1+@q1dmuTERA^oAu`t;1XAK#OXAdOcO+zQZF5I-bXwD8M3NS~tP~%1qo&^k08< zebD3N>}U%FYcHyxc|t)U?R$(ZEL)=8Lh&!)uJwi7&=YW1_%MKYLZhg1U%Opo!@Pfg zSQD;O=Z6EkbzaJCC(Hd6wIpY9`28rI6R{b-M6WUPG{?s)yUO9^g8-_C@L1=bsg1kI zw(!bnnj~Wb=Xvqcug2f?EznAC<53h+R7aU721E>uAS=)k=A^EBlZK$QP^b(@fi`!@ zX}fi0t*zQs>#<88L7rr+^H&8h)~eB=1~rF`#p}mhr6K;D6S9-?S8;!@ph=g&_JJ|Lm7n37(O7zU92d!oB#JzH>8uiav1%4p;SLemdFW;(==@F(FS$XU zHceYJd!A09F`ticsG6~eDGorRSdGu=ph$%o2k(A7(9=vzs|(TqI(ke{v-usNYFo%> zBjXfQc)X(%9CTqzI{VYw7*ZAOAsnK3cGdO=z54u97r;4J17|nPu zOq7Rg`c3-A0^eBR8w-46fp0AEjRn53z}K^5&qu2FrHPVc$Z|Afifi@F z)jei$ttLuuOFH$f1bgp2E{GdE99c`V_ugUaNW> zmi+2lI;CH-|BoH|WKs$WWjpu`(d zapzAhEYxani+NlAqyi93)ac84t;*@tmiT-%xIOiFwPh0uCKrs?X5~*PoG_tqYT@LB ztl|k!#6QDlrg1pU2;h5s&jf#=y_S9)^ixScF8Xoehv6oj2`3OfFC^dDW-Un_P=eo# z0A!i6GmYgi-TyLjGyTZBh|VZk=<{S#ZswIZ-~&Krsix~8S)DjEyk!AW( z#^AfB@5&Z0jI%_9fX%hYd01qA#Ug&IS#d zF~|%PndNCVcyoZxv!cuerkNwm+0zDHGid6du_K04v!+3o zWg=6g0vND99Y0+j<|M&H(N2FsC)2lW@LGj>1_63 z{PGY)Mzhs=L$+YhWxK`gz18Cl+C9EdaFva(bJ|w<0=EYJ4yW6ea3otrodYHbAZi{Ix1aGEx$_3FPos{%6NxURQpI zR_TKRas=zW&gy{A>#GZ%lV4fqbPN$19du8LS}aRZEfm8g_U%M zfI?dgq$H!XH1=a=6qg2ZDNMLfeBVx}{PBP`b)i(7*pJkyDn%xhB5%NX%c1Cu`o8KK zeU+(warCrij2CL&lZu-Y^Pf~aovC?GDxSgA{3sRAWNMz0id&eP&!pl5n3^}F;)qAm zmZ|ta*6>{(mh>>9>LB*^r2g;=n3^Z*8O+$ZM$HdX@#H=fsdx@E&Ic&pOgqrXd0i^~ z5Z2W%K9u$Ji(~k>zQ6LT*`Z!K={3$WMZTHuNRvuSS7yFTO@Da*vqm%D(WXCoHM>sD zGxMEqQZc$R^PPhF!}U8`h*KV^`=TFMz9+ZXc}o@kb1!su%B&xe5bSKr@q`XTH~ z=|8GG=d;fXoWB2l(VzU+IQ_YP{tm~_?Wf%w&t)eJ{yZ23qkTvg8TN&-ay*Mo7$Hjj zAF={tam-CayWc1Q@KTzJ%l`I-DFQwec7BZnBK@npVOuKkA8P`CK^#~W#~Cy3+sGIkocn)6AB zANnNy&M`v3{W23%M&4dUqXk|qZ-_T@dhEYuD5u8h&)uhK9B@sqP@We_`E#xi@@c;) zN(+Jax1SN+ca#4Z$Co7%S7Z5TA%<1Ra-OrF5tpBg=W1QS#pR%^hJA}}1)hr?PNo>* z{3=ObXrNy$@gf7>#N`ZSrw#qCMba-a(3isARNsZv(U1ycL4P6XmmBCG;CL3hPulY_ zX@}oPdcT4G0PxY0Mt?XYI3S202kl|Fa>2{y!!CN#N9u*BSPQ`n#lG zBI7`jq&M^WGS+U8p9MU(pYeLQq~B+tAIa&5oMY!JIDT$BewWM1V#|k$@}H9BnI`2Q zGRXglw8LQoJ|Fa&i>gqq z9Xnfj-PlIU?(*5IYJ3%r8oLX(8$r7RkBSqo2w|VVeku4CTXshv;HbB|y`exoHq4@3 zuUvJtwe`$baSQHUuykUVn_+R7@7R^X<8^p_c!q8lPmk^Vsi~9sYFu{lS{L}|E-qeB zVlP=Z$8Kl#IX5jVUNCPqvoBg)HoIib(#0kA`STWjzqqu-zNC28{1T9q&M%u)Jl|e6 zckT@(OB5pdU0K)zB$ zM!}|Mi91nejR%dcc3899XWejvtdra}jo$r&Z7YI7!K3zRll!SrvGER3z|IR3z%4ay zhoK}u8@7qv+ZMt#zQ1gN9Z&Dw_Uq;>m}g(?7CXI(J>JL?)Pmd)R6e}fk*Ftsvrg{v zX1AxdjBE!i7~sVM_^yi^H6e<6gmJUC{&#UpZ40GazO{z{9IUU!(g2R3fH+pGGwx}A zR)BS#f@-|*!wOvWUXY7pD8LE=?ivSy^2}coVg(`hZTQ9O5>)U4ceUtRtbq2x6TONR z(8hP_oajgpSh!$Et;Y$SJ_rd489}rUE8suq@U_&W1$s;BtX{qqS)_>v@5<3G*EDXHr`oPW{R=TrRZIm12)9OKkUdc`kc zmX8y9#-RAs{rEkI@03o+3@RfPN%5;YyGg)^RPn3(_6GT2Lp{d;2~WoQ(`#r{7sapc z@0ZI56W0m0M176=OC|p-NvGBUc1nJlk5M8Wm_?sc{`tVDOtQF%^@2kAAm*^4z$Al` zI%2!B6#m4#Pd;e6eIzGO{HS^=pj`4RT&+Jed{Z#VF(b&9vCVUU!c zh^uq2J;=a{HE%```(TS_%wZa>bK_-^&me`+i zisV;*X5?4b8*xHyr}))6irOD}pKL#QJC!JpYQHVu)$32Jw-g}*sY@IZzpC8oNcSOn zes#asRU}w&Cy0c6vI8l5G9(5jm7X@Y{jsGTpjQn(MC?Y4m zL-J3N@sGmjc>JsStGGb@OZ6SjD1Q!7U`A>%WE%Ak0gZu#^A#=S2WB%c7%tiW1Kv>q Ao&W#< literal 0 HcmV?d00001 diff --git a/tools/nanokvm_update_edid/nanokvm_update_edid.c b/tools/nanokvm_update_edid/nanokvm_update_edid.c new file mode 100644 index 0000000..4a829ee --- /dev/null +++ b/tools/nanokvm_update_edid/nanokvm_update_edid.c @@ -0,0 +1,749 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/tools/nanokvm_update_edid/nanokvm_update_edid.h b/tools/nanokvm_update_edid/nanokvm_update_edid.h new file mode 100644 index 0000000..ed743fb --- /dev/null +++ b/tools/nanokvm_update_edid/nanokvm_update_edid.h @@ -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 \ No newline at end of file