videomixer: generate EDID
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 11 Nov 2013 16:52:07 +0000 (17:52 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 11 Nov 2013 16:52:07 +0000 (17:52 +0100)
software/videomixer/Makefile
software/videomixer/dvisamplerX.c
software/videomixer/dvisamplerX.h
software/videomixer/edid.c
software/videomixer/edid.h
software/videomixer/fb.c [deleted file]
software/videomixer/fb.h [deleted file]
software/videomixer/main.c
software/videomixer/processor.c [new file with mode: 0644]
software/videomixer/processor.h [new file with mode: 0644]

index 9ec2f7184d53ad5ca73678e2aa72c5805192dcee..9afe6341015315e30736b7bdaba7b10e538eefb7 100644 (file)
@@ -1,7 +1,7 @@
 MSCDIR=../..
 include $(MSCDIR)/software/common.mak
 
-OBJECTS=isr.o fb.o dvisampler0.o dvisampler1.o main.o
+OBJECTS=isr.o processor.o dvisampler0.o dvisampler1.o edid.o main.o
 
 all: videomixer.bin videomixer.fbi
 
index 19ebbbf67f42328eab6ddb08d37ae3b514065e44..636798fc8f71a5acffdba4fdaef839134f8f5531 100644 (file)
@@ -7,13 +7,12 @@
 #include <hw/csr.h>
 #include <hw/flags.h>
 
-#include "fb.h"
 #include "dvisamplerX.h"
 
 #define FRAMEBUFFER_COUNT 4
 #define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1)
 
-static unsigned int dvisamplerX_framebuffers[FRAMEBUFFER_COUNT][1024*768] __attribute__((aligned(16)));
+static unsigned int dvisamplerX_framebuffers[FRAMEBUFFER_COUNT][1280*720] __attribute__((aligned(16)));
 static int dvisamplerX_fb_slot_indexes[2];
 static int dvisamplerX_next_fb_index;
 
@@ -40,7 +39,7 @@ void dvisamplerX_isr(void)
                fb_dmaX_base_write((unsigned int)dvisamplerX_framebuffers[fb_index]);
 }
 
-void dvisamplerX_init_video(void)
+void dvisamplerX_init_video(int hres, int vres)
 {
        unsigned int mask;
 
@@ -52,7 +51,7 @@ void dvisamplerX_init_video(void)
        mask |= 1 << DVISAMPLERX_INTERRUPT;
        irq_setmask(mask);
 
-       dvisamplerX_dma_frame_size_write(fb_hres*fb_vres*4);
+       dvisamplerX_dma_frame_size_write(hres*vres*4);
        dvisamplerX_fb_slot_indexes[0] = 0;
        dvisamplerX_dma_slot0_address_write((unsigned int)dvisamplerX_framebuffers[0]);
        dvisamplerX_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED);
@@ -238,7 +237,6 @@ void dvisamplerX_service(void)
                        dvisamplerX_connected = 0;
                        dvisamplerX_locked = 0;
                        dvisamplerX_clocking_pll_reset_write(1);
-                       dvisamplerX_edid_hpd_en_write(0);
                } else {
                        if(dvisamplerX_locked) {
                                if(dvisamplerX_clocking_locked_read()) {
@@ -263,7 +261,6 @@ void dvisamplerX_service(void)
                if(dvisamplerX_edid_hpd_notif_read()) {
                        printf("dvisamplerX: connected\n");
                        dvisamplerX_connected = 1;
-                       dvisamplerX_edid_hpd_en_write(1);
                        dvisamplerX_clocking_pll_reset_write(0);
                }
        }
index a5c9988f14afc1af1c821f9087885d3472f387c7..300722a6dea2f8dff2bf02699ea298637d64b721 100644 (file)
@@ -2,7 +2,7 @@
 #define __DVISAMPLERX_H
 
 void dvisamplerX_isr(void);
-void dvisamplerX_init_video(void);
+void dvisamplerX_init_video(int hres, int vres);
 void dvisamplerX_print_status(void);
 int dvisamplerX_calibrate_delays(void);
 int dvisamplerX_adjust_phase(void);
index 38cba6d678b808401dae3d2fd99feef59a69b411..4734189c5d629228246e0239aeadbaa2e3a5b039 100644 (file)
@@ -193,7 +193,7 @@ static void generate_unused(uint8_t *data_block)
 }
 
 void generate_edid(void *out,
-       const char mfg_name[3], uint8_t product_code[2], int year,
+       const char mfg_name[3], const char product_code[2], int year,
        const char *name,
        const struct video_timing *timing)
 {
index 5c6b0a3f2d2a421995f375dc70e621d7526eca73..34b1d6241106e2f2264a7e0b54e66ae2e29c1473 100644 (file)
@@ -20,7 +20,7 @@ struct video_timing {
 int validate_edid(const void *buf);
 void get_monitor_name(const void *buf, char *name);
 void generate_edid(void *out,
-       const char mfg_name[3], uint8_t product_code[2], int year,
+       const char mfg_name[3], const char product_code[2], int year,
        const char *name,
        const struct video_timing *timing);
 
diff --git a/software/videomixer/fb.c b/software/videomixer/fb.c
deleted file mode 100644 (file)
index 094cc1f..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-#include <stdio.h>
-
-#include <hw/csr.h>
-#include <hw/flags.h>
-
-#include "fb.h"
-
-int fb_hres = 640;
-int fb_vres = 480;
-
-static void fb_clkgen_write(int cmd, int data)
-{
-       int word;
-
-       word = (data << 2) | cmd;
-       fb_driver_clocking_cmd_data_write(word);
-       fb_driver_clocking_send_cmd_data_write(1);
-       while(fb_driver_clocking_status_read() & CLKGEN_STATUS_BUSY);
-}
-
-void fb_set_mode(int mode)
-{
-       int clock_m, clock_d;
-
-       switch(mode) {
-               default:
-               case FB_MODE_640_480: // Pixel clock: 25MHz
-                       fb_hres = 640;
-                       fb_vres = 480;
-                       clock_m = 2;
-                       clock_d = 4;
-                       fb_fi_hres_write(640);
-                       fb_fi_hsync_start_write(656);
-                       fb_fi_hsync_end_write(752);
-                       fb_fi_hscan_write(800);
-                       fb_fi_vres_write(480);
-                       fb_fi_vsync_start_write(492);
-                       fb_fi_vsync_end_write(494);
-                       fb_fi_vscan_write(525);
-                       break;
-               case FB_MODE_800_600: // Pixel clock: 50MHz
-                       fb_hres = 800;
-                       fb_vres = 600;
-                       clock_m = 2;
-                       clock_d = 2;
-                       fb_fi_hres_write(800);
-                       fb_fi_hsync_start_write(848);
-                       fb_fi_hsync_end_write(976);
-                       fb_fi_hscan_write(1040);
-                       fb_fi_vres_write(600);
-                       fb_fi_vsync_start_write(636);
-                       fb_fi_vsync_end_write(642);
-                       fb_fi_vscan_write(665);
-                       break;
-               case FB_MODE_1024_768: // Pixel clock: 65MHz
-                       fb_hres = 1024;
-                       fb_vres = 768;
-                       clock_m = 13;
-                       clock_d = 10;
-                       fb_fi_hres_write(1024);
-                       fb_fi_hsync_start_write(1048);
-                       fb_fi_hsync_end_write(1184);
-                       fb_fi_hscan_write(1344);
-                       fb_fi_vres_write(768);
-                       fb_fi_vsync_start_write(772);
-                       fb_fi_vsync_end_write(778);
-                       fb_fi_vscan_write(807);
-                       break;
-               case FB_MODE_1920_1080: // Pixel clock: 148MHz
-                       fb_hres = 1920;
-                       fb_vres = 1080;
-                       clock_m = 74;
-                       clock_d = 25;
-                       fb_fi_hres_write(1920);
-                       fb_fi_hsync_start_write(2008);
-                       fb_fi_hsync_end_write(2052);
-                       fb_fi_hscan_write(2200);
-                       fb_fi_vres_write(1080);
-                       fb_fi_vsync_start_write(1084);
-                       fb_fi_vsync_end_write(1089);
-                       fb_fi_vscan_write(1125);
-                       break;
-       }
-       fb_dma0_length_write(fb_hres*fb_vres*4);
-       fb_dma1_length_write(fb_hres*fb_vres*4);
-
-       fb_clkgen_write(0x1, clock_d-1);
-       fb_clkgen_write(0x3, clock_m-1);
-       fb_driver_clocking_send_go_write(1);
-       printf("waiting for PROGDONE...");
-       while(!(fb_driver_clocking_status_read() & CLKGEN_STATUS_PROGDONE));
-       printf("ok\n");
-       printf("waiting for LOCKED...");
-       while(!(fb_driver_clocking_status_read() & CLKGEN_STATUS_LOCKED));
-       printf("ok\n");
-
-       printf("VGA: mode set to %dx%d\n", fb_hres, fb_vres);
-}
-
-void fb_enable(int en)
-{
-       fb_enable_write(!!en);
-}
diff --git a/software/videomixer/fb.h b/software/videomixer/fb.h
deleted file mode 100644 (file)
index 7b9cc92..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __FB_H
-#define __FB_H
-
-enum {
-    FB_MODE_640_480,
-    FB_MODE_800_600,
-    FB_MODE_1024_768,
-    FB_MODE_1920_1080
-};
-
-extern int fb_hres, fb_vres;
-
-void fb_set_mode(int mode);
-void fb_enable(int en);
-
-#endif /* __FB_H */
index 1f79db4a202e8d70c5c6a03d6454496a8bc5bbbd..a4359edde27b0708955e1ebccffc9d82f7e782f3 100644 (file)
@@ -8,9 +8,7 @@
 #include <hw/flags.h>
 #include <console.h>
 
-#include "fb.h"
-#include "dvisampler0.h"
-#include "dvisampler1.h"
+#include "processor.h"
 
 #ifdef POTS_BASE
 static int scale_pot(int raw, int range)
@@ -92,10 +90,10 @@ static void fb_service(void)
        if(readchar_nonblock()) {
                c = readchar();
                if(c == '1') {
-                       fb_enable(1);
+                       fb_enable_write(1);
                        printf("Framebuffer is ON\n");
                } else if(c == '0') {
-                       fb_enable(0);
+                       fb_enable_write(0);
                        printf("Framebuffer is OFF\n");
                }
        }
@@ -119,23 +117,30 @@ static void membw_service(void)
        }
 }
 
+static void list_video_modes(void)
+{
+       char mode_descriptors[PROCESSOR_MODE_COUNT*PROCESSOR_MODE_DESCLEN];
+       int i;
+
+       processor_list_modes(mode_descriptors);
+       for(i=0;i<PROCESSOR_MODE_COUNT;i++)
+               printf("%d: %s\n", i, &mode_descriptors[i*PROCESSOR_MODE_DESCLEN]);
+}
+
 int main(void)
 {
        irq_setmask(0);
        irq_setie(1);
        uart_init();
        
-       puts("Minimal video mixer software built "__DATE__" "__TIME__"\n");
+       printf("Mixxeo software rev. %08x built "__DATE__" "__TIME__"\n\n", GIT_ID);
        
        time_init();
-       fb_set_mode(FB_MODE_1024_768);
-       dvisampler0_init_video();
-       dvisampler1_init_video();
-       fb_enable(1);
+       list_video_modes();
+       processor_start(0);
 
        while(1) {
-               dvisampler0_service();
-               dvisampler1_service();
+               processor_service();
                ui_service();
                fb_service();
                membw_service();
diff --git a/software/videomixer/processor.c b/software/videomixer/processor.c
new file mode 100644 (file)
index 0000000..bb8c6f4
--- /dev/null
@@ -0,0 +1,136 @@
+#include <stdio.h>
+
+#include <hw/csr.h>
+#include <hw/flags.h>
+
+#include "dvisampler0.h"
+#include "dvisampler1.h"
+#include "edid.h"
+#include "processor.h"
+
+static const struct video_timing video_modes[PROCESSOR_MODE_COUNT] = {
+       {
+               .pixel_clock = 6500,
+
+               .h_active = 1024,
+               .h_blanking = 320,
+               .h_sync_offset = 24,
+               .h_sync_width = 136,
+
+               .v_active = 768,
+               .v_blanking = 38,
+               .v_sync_offset = 3,
+               .v_sync_width = 6
+       }, {
+               .pixel_clock = 7425,
+
+               .h_active = 1280,
+               .h_blanking = 370,
+               .h_sync_offset = 220,
+               .h_sync_width = 40,
+
+               .v_active = 720,
+               .v_blanking = 30,
+               .v_sync_offset = 20,
+               .v_sync_width = 5
+       }
+};
+
+void processor_list_modes(char *mode_descriptors)
+{
+       int i;
+       unsigned int refresh_span;
+       unsigned int refresh_rate;
+
+       for(i=0;i<PROCESSOR_MODE_COUNT;i++) {
+               refresh_span = (video_modes[i].h_active + video_modes[i].h_blanking)*(video_modes[i].v_active + video_modes[i].v_blanking);
+               refresh_rate = video_modes[i].pixel_clock*10000/refresh_span;
+               sprintf(&mode_descriptors[PROCESSOR_MODE_DESCLEN*i],
+                       "%ux%u @%uHz", video_modes[i].h_active, video_modes[i].v_active, refresh_rate);
+       }
+}
+
+static void fb_clkgen_write(int cmd, int data)
+{
+       int word;
+
+       word = (data << 2) | cmd;
+       fb_driver_clocking_cmd_data_write(word);
+       fb_driver_clocking_send_cmd_data_write(1);
+       while(fb_driver_clocking_status_read() & CLKGEN_STATUS_BUSY);
+}
+
+static void fb_get_clock_md(unsigned int pixel_clock, unsigned int *m, unsigned int *d)
+{
+       // TODO
+       *m = 13;
+       *d = 10;
+}
+
+static void fb_set_mode(const struct video_timing *mode)
+{
+       unsigned int clock_m, clock_d;
+
+       fb_get_clock_md(mode->pixel_clock, &clock_m, &clock_d);
+
+       fb_fi_hres_write(mode->h_active);
+       fb_fi_hsync_start_write(mode->h_active + mode->h_sync_offset);
+       fb_fi_hsync_end_write(mode->h_active + mode->h_sync_offset + mode->h_sync_width);
+       fb_fi_hscan_write(mode->h_active + mode->h_blanking);
+       fb_fi_vres_write(mode->v_active);
+       fb_fi_vsync_start_write(mode->v_active + mode->v_sync_offset);
+       fb_fi_vsync_end_write(mode->v_active + mode->v_sync_offset + mode->v_sync_width);
+       fb_fi_vscan_write(mode->v_active + mode->v_blanking);
+       
+       fb_dma0_length_write(mode->h_active*mode->v_active*4);
+       fb_dma1_length_write(mode->h_active*mode->v_active*4);
+
+       fb_clkgen_write(0x1, clock_d-1);
+       fb_clkgen_write(0x3, clock_m-1);
+       fb_driver_clocking_send_go_write(1);
+       printf("waiting for PROGDONE...");
+       while(!(fb_driver_clocking_status_read() & CLKGEN_STATUS_PROGDONE));
+       printf("ok\n");
+       printf("waiting for LOCKED...");
+       while(!(fb_driver_clocking_status_read() & CLKGEN_STATUS_LOCKED));
+       printf("ok\n");
+
+       printf("Video mode set to %dx%d\n", mode->h_active, mode->v_active);
+}
+
+static void edid_set_mode(const struct video_timing *mode)
+{
+       unsigned char edid[128];
+       int i;
+
+       generate_edid(&edid, "OHW", "MX", 2013, "Mixxeo ch.A", mode);
+       for(i=0;i<sizeof(edid);i++)
+               MMPTR(DVISAMPLER0_EDID_MEM_BASE+4*i) = edid[i];
+       generate_edid(&edid, "OHW", "MX", 2013, "Mixxeo ch.B", mode);
+       for(i=0;i<sizeof(edid);i++)
+               MMPTR(DVISAMPLER1_EDID_MEM_BASE+4*i) = edid[i];
+}
+
+void processor_start(int mode)
+{
+       const struct video_timing *m = &video_modes[mode];
+
+       fb_enable_write(0);
+       dvisampler0_edid_hpd_en_write(0);
+       dvisampler1_edid_hpd_en_write(0);
+
+       fb_set_mode(m);
+       edid_set_mode(m);
+       dvisampler0_init_video(m->h_active, m->v_active);
+       dvisampler1_init_video(m->h_active, m->v_active);
+
+       fb_enable_write(1);
+       dvisampler0_edid_hpd_en_write(1);
+       dvisampler1_edid_hpd_en_write(1);
+}
+
+void processor_service(void)
+{
+       dvisampler0_service();
+       dvisampler1_service();
+}
diff --git a/software/videomixer/processor.h b/software/videomixer/processor.h
new file mode 100644 (file)
index 0000000..1a09b91
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __PROCESSOR_H
+#define __PROCESSOR_H
+
+#define PROCESSOR_MODE_COUNT 2
+#define PROCESSOR_MODE_DESCLEN 32
+
+void processor_list_modes(char *mode_descriptors);
+void processor_start(int mode);
+void processor_service(void);
+
+#endif /* __VIDEOMODE_H */