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
#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;
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;
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);
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()) {
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);
}
}
#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);
}
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)
{
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);
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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 */
#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)
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");
}
}
}
}
+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();
--- /dev/null
+#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();
+}
--- /dev/null
+#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 */