VGA DDC (not fully tested)
authorlekernel <sebastien.bourdeauducq@lekernel.net>
Thu, 1 Jul 2010 20:11:39 +0000 (22:11 +0200)
committerlekernel <sebastien.bourdeauducq@lekernel.net>
Thu, 1 Jul 2010 20:11:39 +0000 (22:11 +0200)
boards/milkymist-one/rtl/setup.v
boards/milkymist-one/rtl/system.v
boards/milkymist-one/rtl/vga.v
cores/vgafb/rtl/vgafb.v
cores/vgafb/rtl/vgafb_ctlif.v
software/demo/shell.c
software/include/hal/vga.h
software/include/hw/vga.h
software/libhal/vga.c
software/libhal/vin.c

index 98ea007..e58568f 100644 (file)
@@ -21,6 +21,7 @@
  * but when working on a specific part, it's very useful to be
  * able to cut down synthesis times.
  */
+//`define ENABLE_MEMORYCARD
 `define ENABLE_AC97
 `define ENABLE_PFPU
 `define ENABLE_TMU
index 0a791f2..6e053d3 100644 (file)
@@ -883,7 +883,10 @@ vga #(
        .vga_r(vga_r),
        .vga_g(vga_g),
        .vga_b(vga_b),
-       .vga_clk(vga_clk)
+       .vga_clk(vga_clk),
+
+       .vga_sda(vga_sda),
+       .vga_sdc(vga_sdc)
 );
 
 //---------------------------------------------------------------------------
@@ -1196,9 +1199,6 @@ assign videoin_sdc = 1'b0;
 `endif
 
 // TODO
-assign vga_sda = 1'b0;
-assign vga_sdc = 1'b0;
-
 assign mc_d[3:0] = 4'bz;
 assign mc_cmd = 1'bz;
 assign mc_clk = 1'b0;
index 821ef4e..cd9432d 100644 (file)
@@ -49,7 +49,11 @@ module vga #(
        output [7:0] vga_r,
        output [7:0] vga_g,
        output [7:0] vga_b,
-       output vga_clk
+       output vga_clk,
+
+       /* DDC */
+       inout vga_sda,
+       output vga_sdc
 );
 
 wire vga_iclk_dcm;
@@ -144,7 +148,10 @@ vgafb #(
        .vga_vsync_n(vga_vsync_n),
        .vga_r(vga_r),
        .vga_g(vga_g),
-       .vga_b(vga_b)
+       .vga_b(vga_b),
+
+       .vga_sda(vga_sda),
+       .vga_sdc(vga_sdc)
 );
 
 endmodule
index f4e30e9..84bc6bc 100644 (file)
@@ -52,7 +52,9 @@ module vgafb #(
        output reg [7:0] vga_r,
        output reg [7:0] vga_g,
        output reg [7:0] vga_b,
-       output [1:0] vga_clk_sel
+
+       inout vga_sda,
+       output vga_sdc
 );
 
 /*
@@ -104,7 +106,8 @@ vgafb_ctlif #(
        
        .nbursts(nbursts),
 
-       .vga_clk_sel(vga_clk_sel)
+       .vga_sda(vga_sda),
+       .vga_sdc(vga_sdc)
 );
 
 /*
index 2fdedae..52743ad 100644 (file)
@@ -44,9 +44,25 @@ module vgafb_ctlif #(
        
        output reg [17:0] nbursts,
 
-       output reg [1:0] vga_clk_sel
+       inout vga_sda,
+       output reg vga_sdc
 );
 
+/* I2C */
+reg sda_1;
+reg sda_2;
+reg sda_oe;
+reg sda_o;
+
+always @(posedge sys_clk) begin
+       sda_1 <= vga_sda;
+       sda_2 <= sda_1;
+end
+
+assign vga_sda = (sda_oe & ~sda_o) ? 1'b0 : 1'bz;
+
+/* */
+
 reg [fml_depth-1:0] baseaddress_act;
 
 always @(posedge sys_clk) begin
@@ -77,7 +93,10 @@ always @(posedge sys_clk) begin
                baseaddress <= {fml_depth{1'b0}};
                
                nbursts <= 18'd19200;
-               vga_clk_sel <= 2'b00;
+
+               sda_oe <= 1'b0;
+               sda_o <= 1'b0;
+               vga_sdc <= 1'b0;
        end else begin
                csr_do <= 32'd0;
                if(csr_selected) begin
@@ -95,7 +114,11 @@ always @(posedge sys_clk) begin
                                        4'd9: baseaddress <= csr_di[fml_depth-1:0];
                                        // 10: baseaddress_act is read-only for Wishbone
                                        4'd11: nbursts <= csr_di[17:0];
-                                       4'd12: vga_clk_sel <= csr_di[1:0];
+                                       4'd12: begin
+                                               sda_o <= csr_di[1];
+                                               sda_oe <= csr_di[2];
+                                               vga_sdc <= csr_di[3];
+                                       end
                                endcase
                        end
                        
@@ -112,7 +135,7 @@ always @(posedge sys_clk) begin
                                4'd9: csr_do <= baseaddress;
                                4'd10: csr_do <= baseaddress_act;
                                4'd11: csr_do <= nbursts;
-                               4'd12: csr_do <= vga_clk_sel;
+                               4'd12: csr_do <= {vga_sdc, sda_oe, sda_o, sda_2};
                        endcase
                end
        end
index b3169cd..20da1a2 100644 (file)
@@ -162,6 +162,17 @@ static void ls()
        fatfs_done();
 }
 
+static void edid()
+{
+       char buf[256];
+
+       if(!vga_read_edid(buf)) {
+               printf("Failed to read EDID\n");
+               return;
+       }
+       dump_bytes((unsigned int *)buf, 256, 0);
+}
+
 static void render(const char *filename)
 {
        char buffer[8192];
@@ -633,6 +644,7 @@ static void do_command(char *c)
                else if(strcmp(command, "mw") == 0) mw(param1, param2, param3);
                else if(strcmp(command, "ls") == 0) ls();
                else if(strcmp(command, "flush") == 0) flush_bridge_cache();
+               else if(strcmp(command, "edid") == 0) edid();
                else if(strcmp(command, "render") == 0) render(param1);
                else if(strcmp(command, "irender") == 0) {
                        renderer_istart();
index 37a3551..7113474 100644 (file)
@@ -1,16 +1,16 @@
 /*
  * Milkymist VJ SoC (Software)
- * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
- * 
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, version 3 of the License.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
@@ -27,5 +27,6 @@ extern unsigned short int *vga_lastbuffer;
 void vga_init();
 void vga_disable();
 void vga_swap_buffers();
+int vga_read_edid(char *buffer);
 
 #endif /* __HAL_VGA_H */
index dd8d3be..ada7907 100644 (file)
 
 #define CSR_VGA_BURST_COUNT    MMPTR(0x8000302C)
 
+#define CSR_VGA_DDC            MMPTR(0x80003030)
+
+#define VGA_DDC_SDAIN          (0x1)
+#define VGA_DDC_SDAOUT         (0x2)
+#define VGA_DDC_SDAOE          (0x4)
+#define VGA_DDC_SDC            (0x8)
+
 #endif /* __HW_VGA_H */
index 29a3e4c..8e3f285 100644 (file)
@@ -39,6 +39,8 @@ unsigned short int *vga_frontbuffer; /* < buffer currently displayed (or request
 unsigned short int *vga_backbuffer;  /* < buffer currently drawn to, never read by HW */
 unsigned short int *vga_lastbuffer;  /* < buffer displayed just before (or HW finishing last scan) */
 
+static int i2c_init();
+
 void vga_init()
 {
        vga_hres = 640;
@@ -56,6 +58,10 @@ void vga_init()
        printf("VGA: initialized at resolution %dx%d\n", vga_hres, vga_vres);
        printf("VGA: framebuffers at 0x%08x 0x%08x 0x%08x\n",
                (unsigned int)&framebufferA, (unsigned int)&framebufferB, (unsigned int)&framebufferC);
+       if(i2c_init())
+               printf("VGA: DDC I2C bus initialized\n");
+       else
+               printf("VGA: DDC I2C bus initialization problem\n");
 }
 
 void vga_disable()
@@ -82,3 +88,137 @@ void vga_swap_buffers()
        
        CSR_VGA_BASEADDRESS = (unsigned int)vga_frontbuffer;
 }
+
+/* DDC */
+int i2c_started;
+
+static int i2c_init()
+{
+       unsigned int timeout;
+
+       i2c_started = 0;
+       CSR_VGA_DDC = VGA_DDC_SDC;
+       /* Check the I2C bus is ready */
+       timeout = 1000;
+       while((timeout > 0) && (!(CSR_VGA_DDC & VGA_DDC_SDAIN))) timeout--;
+
+       return timeout;
+}
+
+static void i2c_delay()
+{
+       unsigned int i;
+
+       for(i=0;i<1000;i++) __asm__("nop");
+}
+
+/* I2C bit-banging functions from http://en.wikipedia.org/wiki/I2c */
+static unsigned int i2c_read_bit()
+{
+       unsigned int bit;
+
+       /* Let the slave drive data */
+       CSR_VGA_DDC = 0;
+       i2c_delay();
+       CSR_VGA_DDC = VGA_DDC_SDC;
+       i2c_delay();
+       bit = CSR_VGA_DDC & VGA_DDC_SDAIN;
+       i2c_delay();
+       CSR_VGA_DDC = 0;
+       return bit;
+}
+
+static void i2c_write_bit(unsigned int bit)
+{
+       if(bit) {
+               CSR_VGA_DDC = VGA_DDC_SDAOE|VGA_DDC_SDAOUT;
+       } else {
+               CSR_VGA_DDC = VGA_DDC_SDAOE;
+       }
+       i2c_delay();
+       /* Clock stretching */
+       CSR_VGA_DDC |= VGA_DDC_SDC;
+       i2c_delay();
+       CSR_VGA_DDC &= ~VGA_DDC_SDC;
+}
+
+static void i2c_start_cond()
+{
+       if(i2c_started) {
+               /* set SDA to 1 */
+               CSR_VGA_DDC = VGA_DDC_SDAOE|VGA_DDC_SDAOUT;
+               i2c_delay();
+               CSR_VGA_DDC |= VGA_DDC_SDC;
+       }
+       /* SCL is high, set SDA from 1 to 0 */
+       CSR_VGA_DDC = VGA_DDC_SDAOE|VGA_DDC_SDC;
+       i2c_delay();
+       CSR_VGA_DDC = VGA_DDC_SDAOE;
+       i2c_started = 1;
+}
+
+static void i2c_stop_cond()
+{
+       /* set SDA to 0 */
+       CSR_VGA_DDC = VGA_DDC_SDAOE;
+       i2c_delay();
+       /* Clock stretching */
+       CSR_VGA_DDC = VGA_DDC_SDAOE|VGA_DDC_SDC;
+       /* SCL is high, set SDA from 0 to 1 */
+       CSR_VGA_DDC = VGA_DDC_SDC;
+       i2c_delay();
+       i2c_started = 0;
+}
+
+static unsigned int i2c_write(unsigned char byte)
+{
+       unsigned int bit;
+       unsigned int ack;
+
+       for(bit = 0; bit < 8; bit++) {
+               i2c_write_bit(byte & 0x80);
+               byte <<= 1;
+       }
+       ack = !i2c_read_bit();
+       return ack;
+}
+
+static unsigned char i2c_read(int ack)
+{
+       unsigned char byte = 0;
+       unsigned int bit;
+
+       for(bit = 0; bit < 8; bit++) {
+               byte <<= 1;
+               byte |= i2c_read_bit();
+       }
+       i2c_write_bit(!ack);
+       return byte;
+}
+
+int vga_read_edid(char *buffer)
+{
+       int i;
+
+       i2c_start_cond();
+       if(!i2c_write(0xA0)) {
+               printf("VGA: No ack for 0xA0 address\n");
+               return 0;
+       }
+       if(!i2c_write(0x00)) {
+               printf("VGA: No ack for EDID offset\n");
+               return 0;
+       }
+       i2c_start_cond();
+       if(!i2c_write(0xA1)) {
+               printf("VGA: No ack for 0xA1 address\n");
+               return 0;
+       }
+       
+       for(i=0;i<255;i++)
+               buffer[i] = i2c_read(1);
+       buffer[255] = i2c_read(0);
+       i2c_stop_cond();
+
+       return 1;
+}
index 67e1aab..4bd6302 100644 (file)
@@ -69,7 +69,7 @@ static void i2c_write_bit(unsigned int bit)
        CSR_BT656CAP_I2C &= ~BT656CAP_I2C_SDC;
 }
 
-static void i2c_start_cond(void)
+static void i2c_start_cond()
 {
        if(i2c_started) {
                /* set SDA to 1 */
@@ -84,7 +84,7 @@ static void i2c_start_cond(void)
        i2c_started = 1;
 }
 
-static void i2c_stop_cond(void)
+static void i2c_stop_cond()
 {
        /* set SDA to 0 */
        CSR_BT656CAP_I2C = BT656CAP_I2C_SDAOE;