I don't know if this was the correct way to do it, but I seem to have it fully working now. There were many issues.
My custom board is derived from the DM6467, and includes the THS8200. I have it producing VGA 640x480 60Hz output that I can see on a computer monitor. I figured it out based on my own research, as well as a quick comment from Brijesh Jadav80 on 06-15-2011 8:17AM at http://e2e.ti.com/support/embedded/f/354/p/116736/414361.aspx#414361 . Otherwise no help from the forum was forthcoming in a timely manner :(
Below are the major areas that I had to modify to get this working.
APPLICATION PROGRAM:
I had wanted to use an RGB mode, but VPIF doesn't support it. More specifically, neither ColorSpace_RGB565 nor ColorSpace_RGB888 are supported. I tentatively got working a mode where the THS8200 was expecting 16-bit RGB 4:4:4 (which is RGB565 encoding), but the DaVinci was thinking it was sending YUV422. To cope with this, my application program faked it by stuffing the RGB565 data into Y and CbCr buffer locations, per the implicit map that the THS8200 uses as seen in Figure 4-3 about 16-bit RGB 4:4:4 format.
HOWEVER, I soon realized the better method was to configure the THS8200 for 20-bit YCbCr 4:2:2, which directly receives the application data in ColorSpace_YUV422PSEMI format. In this format, my old test code that previously sent NTSC out from an ADV7171 worked all the same in setting up test buffers of video data.
CLOCKING:
Modified git/arch/arm/mach-davinci/cdce949.c to produce a 25.175MHz pixel clock that my circuit delivers from the CDCE949 to the DM6467 VPIF_CLKIN2 signal. This required a few code changes:
static struct cdce_freq_table freq_table[] = {
TABLE(13500),
TABLE(16875),
TABLE(25175), /*added by HgF*/
TABLE(27000),
TABLE(54000),
TABLE(81000),
TABLE(74250),
TABLE(148000),
};
DMAI MODIFICATIONS:
The file dvsdk/dvsdk_3_10_00_11/dmai_2_10_00_05/packages/ti/sdo/dmai/linux/Display_v4l2.c has an array v4l2_std_id_stds[] that maps the video standard numbers used by DMAI to the video standards used by VPIF. VideoStd_VGA is already defined somewhere in DMAI as being a 4, but the v4l2_std_id_stds[] array has a zero in that position. I changed that 0 to match the #define I would soon define in git/include/media/davinci/videohd.h:
static v4l2_std_id stds[VideoStd_COUNT] = { 0, 0, 0, 0, V4L2_STD_VGA640x480_60/*added by HgF, was 0*/, V4L2_STD_NTSC,
V4L2_STD_PAL, V4L2_STD_525P_60, V4L2_STD_625P_50, V4L2_STD_720P_60,
V4L2_STD_720P_50, 0, V4L2_STD_1080I_60, V4L2_STD_1080I_50,
0, 0, 0, V4L2_STD_1080P_60, V4L2_STD_1080P_50 };
VPIF MODIFICATIONS:
I had to modify git/include/media/davinci/videohd.h to define a standard for VGA. I did it by adding a new line below the TV standards:
#define V4L2_STD_VGA640x480_60 ((v4l2_std_id)(0x0100000000000000ULL)) /*added by HgF*/
Then, in git/drivers/media/video/davinci/vpif_display.c I had to add a new entry to the array struct vpif_channel_config_params ch_params[]. This array is searched for standard ID's such as the new one I added for V4L2_STD_VGA640x480_60. I think the entries can be in any order. I added my new one to the bottom (end). I also broke out some comments:
{ // Added by HgF
"VGA 640x480 60Hz",
640, /*width*/
480, /*height*/
60, /*Hz*/
1, /*progressive*/
0, /* VPIF parameter, 0=y/c not muxed, use 2 channels. 1=y/c muxed, use 1 channel.*/
* These are VPIF parameters. See VPIF Users Guide Figures 4, 5, 39 and Tables 6-9, etc */
/* Since this array entry for VGA is progressive, Figure VPIF Users Guide Figure 5 is the one to use */
/* Useful VGA timing diagram posted by MBedder at http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102783 */
/* Horizontal Timing: 8 pixels front porch, 96 pixels horiz sync, 40 pixels back porch, 8 pixels left border, 640 pixels video 8 pixels right border; 800 pixels total */
/* Vertical Timing: 2 lines front porch, 2 lines vert sync, 25 lines back porch, 8 lines top border, 480 lines video, 8 lines bottom border; 525 lines total */
/* Regarding eav2sav & sav2sav: For NTSC, 27MHz data div by 29.97 fps yields 900900 data bits/frame. Div by 525 lines yields 1716 bits/line... */
/* Where px = pixel or bit time; eav2sav=268px, sav2eav=1440px, eav=4px, sav=4px; Therefore eav+eav2sav+sav+sav2eav = eav2sav+sav2eav+8 = 1716, which matchines
16 bits/line above */
/* Calculate eav2sav & sav2eav for VGA, in case VPIF uses it. 800px/line, 640 px/line, therefore blanking=160px, less eav+sav leaves eav2sav=152px, also sav2eav=800-8-
v2sav=640, yep*/
152, /* eav2sav. length of eav 2 sav */
640, /* sav2eav. length of sav 2 eav */
/* VPIF doc doesn't describe physical vertical sync signal very well. Let's assume first field starts at beginning of vertical sync pulse. */
/* Therefore, active video starts after 2 lines of vert sync, 25 lines back porch, 8 lines top border; which totals 35. Thus active video starts on line 36*/
/* Then field=frame continues for 480 lines, such that first line of lower blanking is at line 516. */
/* This is then followed by 8 lines bottom border, 2 lines front porch, which is 10 lines. So last line is 516+10-1 = 525, yep */
1, /* L1. first line of upper blanking, top field, always 1. */
28, /* L3. first line of active video, top field. */
508, /* L5. first line of lower blanking, top field. */
0, /* L7. first line of upper blanking, bottom field, not used if progressive. */
0, /* L9. first line of active video, bottom field, not used if progressive. */
0, /* L11. first line of lower blanking, bottom field, not used if progressive. */
525, /* vsize. number of lines per frame, equals last line of bottom field (equals last line of top and only field if progressive) */
0, /* capture_format */
0, /* no vbi */
0, /* hd_sd */
V4L2_STD_VGA640x480_60,
25175000 /* clk_rate ??? can't confirm this with scope */
} // Added by HgF
Finally, over in the git/drivers/media/video/ths8200.c I had to add new array entry to struct ths8200_mode_info mode_info[] in order to support the VGA mode. I also embedded a lot of comments to help me figure out what in the world was going on:
/* VGA Modes - added by HgF */
{
V4L2_STD_VGA640x480_60, /* "std". Standard added by HgF, for doing VGA at 640x480 pixels, 60Hz frames, VESA compatible */
#if 0
THS8200_INTF_16BIT_RGB, /* "input_intf". Interface 16-Bit RGB 4:4:4 Data Format (THS8200 datasheet Figure 4-3) */
#else
THS8200_INTF_20BIT_YUV422, /* "input_intf". Interface 20-bit YCbCr 4:2:2 Data Format (THS8200 datasheet Figure 4-2) */
#endif
THS8200_VESA_MASTER /* "mode". THS8200 originates timing. In THS8200_VESA_SLAVE mode, THS8200 uses input sync signals for timing */,
/* See http://www.epanorama.net/faq/vga2rgb/calc.html and bottom of page 38 of http://www.ti.com/lit/an/spraan0/spraan0.pdf */
/* See http://e2e.ti.com/support/data_converters/videoconverters/f/376/t/113249.aspx */
525, /* "frame_size". SEE BELOW "THS8200 REGISTER VALUES FOR 640x480 VGA" */
525, /* "field_size". SEE BELOW "THS8200 REGISTER VALUES FOR 640x480 VGA" */
800, /* "pixels_per_line". SEE BELOW "THS8200 REGISTER VALUES FOR 640x480 VGA" */
0, /* "hs_in_delay". SEE BELOW "THS8200 REGISTER VALUES FOR 640x480 VGA" */
0x2C, /* "negative_hsync_width" "dtg1_spec_a" ???????????*/
0x2C, /* "positive_hsync_width" "dtg1_spec_c" ???????????*/
0x84, /* "hfront_porch" "dtg1_spec_d" ????????????*/
0x58, /* "hback_porch" "dtg1_spec_b" ????????????*/
0xC0, /* "vfront_porch" "dtg1_spec_e", was 0xC0 but should perhaps be 0x8A*/
0x00, /* "pulse_duration" "dtg1_spec_h" ???????????*/
0x00, /* "full_line_pulse_duration" "dtg1_spec_i" ???????????*/
0x58, /* "vback_porch" "dtg1_spec_k" ??????????????*/
0x00, /* "dtg_spec_k1" ???????????????*/
0 /* "vs_in_delay". SEE BELOW "THS8200 REGISTER VALUES FOR 640x480 VGA" */
}
/* Useful VGA timing diagram posted by MBedder at http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102783 */
/* Horizontal Timing: 8 pixels front porch, 96 pixels horiz sync, 40 pixels back porch, 8 pixels left border, 640 pixels video 8 pixels right border; 800 pixels total */
/* Vertical Timing: 2 lines front porch, 2 lines vert sync, 25 lines back porch, 8 lines top border, 480 lines video, 8 lines bottom border; 525 lines total */
/*
THS8200 REGISTER VALUES FOR 640x480 VGA
From http://e2e.ti.com/support/data_converters/videoconverters/f/376/t/113249.aspx
Compare to datasheet definitions of sub-address and value, including around page 63 of datasheet.
If the FID input pin is pulled or driven low for progressive discrete sync formats, use REG36h=80h when FID polarity is set to low polarity in REG 82h.
(MHB/HHS has FID pin pulled to 3.3V via 10K resistor. For VGA Master mode, FID pin unused. I believe REG36h=00h is correct.)
Sub-address; value
0x03; 0xC1
0x19; 0x03
0x1C; 0x70
0x34; 0x03 *combined with reg below makes dtg1_total_pixels=800*
0x35; 0x20
0x36; 0x00 *see FID above*
0x37; 0x01
0x38; 0x87 *dtg1_mode register dtg1_on=0x80, dtg1_pass_through=0x10 (not set in this case), dtg1_mode=0x07 (VESA Slave Mode)*
0x39; 0x22 *combined with two regs below makes dtg1_frame_size=525 and dtg1_field_size=525*
0x3A; 0x0D
0x3B; 0x0D
0x3C; 0x80
0x4A; 0x8C
0x4B; 0x44
0x4C; 0x00
0x4D; 0x00
0x4E; 0x00
0x4F; 0xC0
0x70; 0x60
0x71; 0x00
0x72; 0x01
0x73; 0x03
0x74; 0x00
0x75; 0x01
0x76; 0x00
0x77; 0x07
0x78; 0xFF
0x79; 0x00 *combined with reg below makes dtg2_hs_in_dly=0*
0x7A; 0x00
0x7B; 0x00 *combined with reg below makes dtg2_vs_in_dly=0*
0x7C; 0x00
0x82; 0x43
*/
This did cause VGA format to come out, but the horizontal and vertical syncs were in the wrong place. Changing the dtg1_spec_e above seemed to have no effect. Instead, getting a little weary, I inserted the following code rather than upgrading the whole table definition. It seemed that I needed to change dtg2_vdly1 and dtg2_hdly. I added code to the ths8200_setstd() function, near the end and just before the THS8200_CHIP_CTL twiddle, that I've repeated below for location reference.
if (V4L2_STD_VGA640x480_60 == mode_info[i].std) { /* added by HgF */
int vdly1 = 11;
int hdly = 68;
#define THS8200_DTG2_VDLY1_LSB_MASK (0xFF)
#define THS8200_DTG2_VDLY1_MSB_MASK (0x07)
#define THS8200_DTG2_HDLY_LSB_MASK (0xFF)
#define THS8200_DTG2_HDLY_MSB_MASK (0x1F)
printk(KERN_CRIT "{HgF ths8200_setstd()} V4L2_STD_VGA640x480_60 explicitly recognized, vdly1=%d, hdly=%d\n", (int)vdly1, (int)hdly); /* added by HgF */
err |= ths8200_write(sd, THS8200_DTG2_VDLY1_LSB,
(vdly1 & THS8200_DTG2_VDLY1_LSB_MASK));
value = ths8200_read(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB);
value &= 0xF8;
value |= ((vdly1 >> 8) & THS8200_DTG2_VDLY1_MSB_MASK);
err |= ths8200_write(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, value);
err |= ths8200_write(sd, THS8200_DTG2_HLENGTH_HDLY_LSB, /*FYI, THS8200_DTG2_HLENGTH_HDLY_LSB inconsistently named. Should be THS8200_DTG2_HDLY_LSB */
(hdly & THS8200_DTG2_HDLY_LSB_MASK));
value = ths8200_read(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB);
value &= 0xE0;
value |= ((hdly >> 8) & THS8200_DTG2_HDLY_MSB_MASK);
err |= ths8200_write(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, value);
}
ths8200_write(sd, THS8200_CHIP_CTL, 0x00);
mdelay(10);
ths8200_write(sd, THS8200_CHIP_CTL, 0x01);
I might have missed something, but I think I got it all. With all those changes, my splash application (derived from decode demo) can now display a fixed image on a VGA monitor, going from the DaVinci DM6467 through the VPIF and THS8200.
-Helmut