From 8f0c9bd8cc05f7e97c3888946a70492ef4461919 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Sat, 4 Jan 2020 14:57:47 +0800 Subject: [PATCH] Support linux FB over VGA/Direct Video. --- menu.cpp | 2 +- user_io.cpp | 13 ++++++ user_io.h | 3 ++ video.cpp | 114 +++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/menu.cpp b/menu.cpp index 76172fc..82dc94a 100644 --- a/menu.cpp +++ b/menu.cpp @@ -5164,7 +5164,7 @@ void Info(const char *message, int timeout, int width, int height, int frame) if (!user_io_osd_is_visible()) { OSD_PrintInfo(message, &width, &height, frame); - InfoEnable(20, 10, width, height); + InfoEnable(20, (cfg.direct_video && get_vga_fb()) ? 30 : 10, width, height); OsdSetSize(16); menu_timer = GetTimer(timeout); diff --git a/user_io.cpp b/user_io.cpp index d6139e8..9096d7f 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -1955,6 +1955,18 @@ char user_io_user_button() return (cur_btn & BUTTON_USR) ? 1 : 0; } +static int vga_fb = 0; +void set_vga_fb(int enable) +{ + vga_fb = enable; + user_io_send_buttons(1); +} + +int get_vga_fb() +{ + return vga_fb; +} + static char kbd_reset = 0; void user_io_send_buttons(char force) { @@ -1977,6 +1989,7 @@ void user_io_send_buttons(char force) if (cfg.hdmi_limited & 1) map |= CONF_HDMI_LIMITED1; if (cfg.hdmi_limited & 2) map |= CONF_HDMI_LIMITED2; if (cfg.direct_video) map |= CONF_DIRECT_VIDEO; + if (vga_fb) map |= CONF_VGA_FB; if ((map != key_map) || force) { diff --git a/user_io.h b/user_io.h index 20227ee..e30c14f 100644 --- a/user_io.h +++ b/user_io.h @@ -149,6 +149,7 @@ #define CONF_VGA_SOG 0b0000001000000000 #define CONF_DIRECT_VIDEO 0b0000010000000000 #define CONF_HDMI_LIMITED2 0b0000100000000000 +#define CONF_VGA_FB 0b0001000000000000 // core type value should be unlikely to be returned by broken cores #define CORE_TYPE_UNKNOWN 0x55 @@ -244,6 +245,8 @@ void user_io_analog_joystick(unsigned char, char, char); void user_io_set_joyswap(int swap); int user_io_get_joyswap(); char user_io_osd_is_visible(); +void set_vga_fb(int enable); +int get_vga_fb(); void user_io_send_buttons(char); uint16_t user_io_get_sdram_cfg(); diff --git a/video.cpp b/video.cpp index 7c6f18c..a4f774b 100644 --- a/video.cpp +++ b/video.cpp @@ -42,6 +42,11 @@ #define FB_FMT_RxB 0b10000 #define FB_EN 0x8000 +#define FB_DV_LBRD 3 +#define FB_DV_RBRD 6 +#define FB_DV_UBRD 2 +#define FB_DV_BBRD 2 + static volatile uint32_t *fb_base = 0; static int fb_enabled = 0; @@ -77,6 +82,14 @@ vmode_t vmodes[] = }; #define VMODES_NUM (sizeof(vmodes) / sizeof(vmodes[0])) +vmode_t tvmodes[] = +{ + {{ 640, 16, 96, 48, 240, 4, 4, 14 }, 12.587 }, //NTSC 15K + {{ 640, 16, 96, 48, 480, 8, 4, 33 }, 25.175 }, //NTSC 31K + {{ 640, 16, 96, 48, 288, 6, 4, 14 }, 12.587 }, //PAL 15K + {{ 640, 16, 96, 48, 576, 2, 4, 42 }, 25.175 }, //PAL 31K +}; + struct vmode_custom_t { uint32_t item[32]; @@ -404,19 +417,31 @@ static void set_video(vmode_custom_t *v, double Fpix) loadScalerCfg(); setScaler(); + v_cur = *v; + + vmode_custom_t v_fix = v_cur; + if (cfg.direct_video) + { + v_fix.item[2] = FB_DV_RBRD; + v_fix.item[4] = FB_DV_LBRD; + v_fix.item[1] += v_cur.item[2] - v_fix.item[2]; + v_fix.item[1] += v_cur.item[4] - v_fix.item[4]; + + v_fix.item[6] = FB_DV_BBRD; + v_fix.item[8] = FB_DV_UBRD;; + v_fix.item[5] += v_cur.item[6] - v_fix.item[6]; + v_fix.item[5] += v_cur.item[8] - v_fix.item[8]; + } + printf("Send HDMI parameters:\n"); spi_uio_cmd_cont(UIO_SET_VIDEO); printf("video: "); for (int i = 1; i <= 8; i++) { - v_cur.item[i] = v->item[i]; - spi_w(v_cur.item[i]); - printf("%d, ", v_cur.item[i]); + spi_w(v_fix.item[i]); + printf("%d(%d), ", v_cur.item[i], v_fix.item[i]); } - for (int i = 9; i < 21; i++) v_cur.item[i] = v->item[i]; - v_cur.Fpix = v->Fpix; - if(Fpix) setPLL(Fpix, &v_cur); printf("\nPLL: "); @@ -548,9 +573,26 @@ void video_mode_load() printf("Disabling vsync_adjust because of enabled direct video.\n"); cfg.vsync_adjust = 0; } - vmode_def = store_custom_video_mode(cfg.video_conf, &v_def); - vmode_pal = store_custom_video_mode(cfg.video_conf_pal, &v_pal); - vmode_ntsc = store_custom_video_mode(cfg.video_conf_ntsc, &v_ntsc); + + if (cfg.direct_video) + { + int mode = cfg.menu_pal ? 2 : 0; + if (cfg.forced_scandoubler) mode++; + + v_def.item[0] = mode; + for (int i = 0; i < 8; i++) v_def.item[i + 1] = tvmodes[mode].vpar[i]; + setPLL(tvmodes[mode].Fpix, &v_def); + + vmode_def = 1; + vmode_pal = 0; + vmode_ntsc = 0; + } + else + { + vmode_def = store_custom_video_mode(cfg.video_conf, &v_def); + vmode_pal = store_custom_video_mode(cfg.video_conf_pal, &v_pal); + vmode_ntsc = store_custom_video_mode(cfg.video_conf_ntsc, &v_ntsc); + } set_video(&v_def, 0); } @@ -708,6 +750,7 @@ void video_fb_enable(int enable, int n) { if (fb_base) { + if (cfg.direct_video) set_vga_fb(enable); int res = spi_uio_cmd_cont(UIO_SET_FBUF); if (res) { @@ -722,16 +765,23 @@ void video_fb_enable(int enable, int n) uint32_t fb_addr = FB_ADDR + (FB_SIZE * 4 * n) + (n ? 0 : 4096); fb_num = n; + int xoff = 0, yoff = 0; + if (cfg.direct_video) + { + xoff = v_cur.item[4] - FB_DV_LBRD; + yoff = v_cur.item[8] - FB_DV_UBRD; + } + printf("Switch to HPS frame buffer\n"); spi_w((uint16_t)(FB_EN | FB_FMT_RxB | FB_FMT_8888)); // format, enable flag spi_w((uint16_t)fb_addr); // base address low word spi_w(fb_addr >> 16); // base address high word spi_w(fb_width); // frame width spi_w(fb_height); // frame height - spi_w(0); // scaled left - spi_w(v_cur.item[1] - 1); // scaled right - spi_w(0); // scaled top - spi_w(v_cur.item[5] - 1); // scaled bottom + spi_w(xoff); // scaled left + spi_w(xoff + v_cur.item[1] - 1); // scaled right + spi_w(yoff); // scaled top + spi_w(yoff + v_cur.item[5] - 1); // scaled bottom printf("HPS frame buffer: %dx%d, stride = %d bytes\n", fb_width, fb_height, fb_stride); if (!fb_num) @@ -1301,13 +1351,24 @@ void video_cmd(char *cmd) if (width < 120 || width > (int)v_cur.item[1]) width = v_cur.item[1]; if (height < 120 || height > (int)v_cur.item[5]) height = v_cur.item[5]; - div = 1; - while ((width*(div + 1)) <= (int)v_cur.item[1] && (height*(div + 1)) <= (int)v_cur.item[5]) div++; + int divx = 1; + int divy = 1; + if (cfg.direct_video && (v_cur.item[5] < 300)) + { + // TV 240P/288P + while ((width*(divx + 1)) <= (int)v_cur.item[1]) divx++; + while ((height*(divy + 1)) <= (int)v_cur.item[5]) divy++; + } + else + { + while ((width*(divx + 1)) <= (int)v_cur.item[1] && (height*(divx + 1)) <= (int)v_cur.item[5]) divx++; + divy = divx; + } - hmin = (uint16_t)((v_cur.item[1] - (width * div)) / 2); - vmin = (uint16_t)((v_cur.item[5] - (height * div)) / 2); - hmax = hmin + (width * div) - 1; - vmax = vmin + (height * div) - 1; + hmin = (uint16_t)((v_cur.item[1] - (width * divx)) / 2); + vmin = (uint16_t)((v_cur.item[5] - (height * divy)) / 2); + hmax = hmin + (width * divx) - 1; + vmax = vmin + (height * divy) - 1; accept = 1; } @@ -1357,16 +1418,23 @@ void video_cmd(char *cmd) uint32_t addr = FB_ADDR + 4096; + int xoff = 0, yoff = 0; + if (cfg.direct_video) + { + xoff = v_cur.item[4] - FB_DV_LBRD; + yoff = v_cur.item[8] - FB_DV_UBRD; + } + spi_uio_cmd_cont(UIO_SET_FBUF); spi_w(FB_EN | sc_fmt); // format, enable flag spi_w((uint16_t)addr); // base address low word spi_w(addr >> 16); // base address high word spi_w(width); // frame width spi_w(height); // frame height - spi_w(hmin); // scaled left - spi_w(hmax); // scaled right - spi_w(vmin); // scaled top - spi_w(vmax); // scaled bottom + spi_w(xoff + hmin); // scaled left + spi_w(xoff + hmax); // scaled right + spi_w(yoff + vmin); // scaled top + spi_w(yoff + vmax); // scaled bottom DisableIO(); if (cmd[6] != '2')