From 746549f088fd65f560a8f25efd2c08ac7c283ca3 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Fri, 15 Dec 2017 16:42:03 +0800 Subject: [PATCH] Another, more simplified way to define custom HDMI video mode. --- MiSTer.ini | 4 +++ user_io.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 95 insertions(+), 4 deletions(-) diff --git a/MiSTer.ini b/MiSTer.ini index 13ea8ed..7ca1eea 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -24,6 +24,10 @@ dvi_mode=0 ; set to 1 for DVI mode. Audio won't be transmitted throu ; 5 - 800x600@60 ; 6 - 640x480@60 ; 7 - 1280x720@50 +; ; custom mode: 0,hact,hfp,hs,hbp,vact,vfp,vs,vbp,4,M,3,N,5,C0,9,CP,8,BW,7,Mfrac ; 0,1280,48,112,248,1024,1,3,38,4,1028,3,65536,5,514,9,2,8,7,7,0xA3D709E8 +; +; custom mode: 1,hact,hfp,hs,hbp,vact,vfp,vs,vbp,Fpix +; 1,1280,48,112,248,1024,1,3,38,108 video_mode=0 diff --git a/user_io.c b/user_io.c index 8e03dfe..d5d879a 100644 --- a/user_io.c +++ b/user_io.c @@ -1928,6 +1928,57 @@ emu_mode_t user_io_get_kbdemu() return emu_mode; } +int getPLL(double Fout, uint32_t *M, uint32_t *K, uint32_t *C) +{ + uint32_t c = 1; + while ((Fout*c) < 400) c++; + + printf("Calculate PLL for %.2f MHz:\n",Fout); + + while (1) + { + printf("C=%d, ", c); + *C = c; + + double fvco = Fout*c; + printf("Fvco=%f, ", fvco); + + uint32_t m = (uint32_t)(fvco / 50); + printf("M=%d, ", m); + *M = m; + + double ko = ((fvco / 50) - m); + printf("K_orig=%f, ", ko); + + uint32_t k = (uint32_t)(ko * 4294967296); + if (!k) k = 1; + printf("K=%u. ", k); + *K = k; + + if (ko && (ko <= 0.05f || ko >= 0.95f)) + { + if (fvco > 1500.f) + { + printf("Fvco > 1500MHz. Cannot calculate PLL parameters!"); + return 0; + } + printf("K_orig is outside desired range try next C0\n"); + c++; + } + else + { + printf("\n"); + return 1; + } + } +} + +uint32_t getPLLdiv(uint32_t div) +{ + if (div & 1) return 0x20000 | (((div / 2)+1) << 8) | (div / 2); + return ((div / 2) << 8) | (div / 2); +} + void parse_video_mode() { char *cfg = mist_cfg.video_conf; @@ -1939,6 +1990,33 @@ void parse_video_mode() while (*cfg) { char *next; + if (cnt == 9 && items[0] == 1) + { + double Fout = strtod(cfg, &next); + if (cfg == next || (Fout < 20.f || Fout > 200.f)) + { + printf("Error parsing video_mode parameter: ""%s""\n", mist_cfg.video_conf); + return; + } + + uint32_t M, K, C; + if (!getPLL(Fout, &M, &K, &C)) return; + + items[9] = 4; + items[10] = getPLLdiv(M); + items[11] = 3; + items[12] = 0x10000; + items[13] = 5; + items[14] = getPLLdiv(C); + items[15] = 9; + items[16] = 2; + items[17] = 8; + items[18] = 7; + items[19] = 7; + items[20] = K; + break; + } + uint32_t val = strtoul(cfg, &next, 0); if (cfg == next || (*next !=',' && *next)) { @@ -1959,22 +2037,30 @@ void parse_video_mode() return; } - if (cnt < 21 || cnt > 32) + if ((items[0]==0 && cnt < 21) || (items[0]==1 && cnt < 9)) { printf("Incorrect amount of items in video_mode parameter: %d\n", cnt); return; } - if (items[0]) + if (items[0]>1) { printf("Incorrect video_mode parameter\n"); return; } + printf("Send HDMI parameters:\n"); spi_uio_cmd_cont(UIO_SET_VIDEO); - for (int i = 1; i <= 8; i++) spi_w(items[i]); - for (int i = 9; i < cnt; i++) + printf("video: "); + for (int i = 1; i <= 8; i++) { + spi_w(items[i]); + printf("%d, ", items[i]); + } + printf("\nPLL: "); + for (int i = 9; i < 21; i++) + { + printf("0x%X, ", items[i]); if (i & 1) spi_w(items[i]); else { @@ -1982,5 +2068,6 @@ void parse_video_mode() spi_w(items[i] >> 16); }; } + printf("\n"); DisableIO(); }