Home | History | Annotate | Line # | Download | only in videomode
edid.c revision 1.3.12.3
      1  1.3.12.3  yamt /* $NetBSD: edid.c,v 1.3.12.3 2007/09/03 14:39:29 yamt Exp $ */
      2  1.3.12.2  yamt 
      3  1.3.12.2  yamt /*-
      4  1.3.12.2  yamt  * Copyright (c) 2006 Itronix Inc.
      5  1.3.12.2  yamt  * All rights reserved.
      6  1.3.12.2  yamt  *
      7  1.3.12.2  yamt  * Written by Garrett D'Amore for Itronix Inc.
      8  1.3.12.2  yamt  *
      9  1.3.12.2  yamt  * Redistribution and use in source and binary forms, with or without
     10  1.3.12.2  yamt  * modification, are permitted provided that the following conditions
     11  1.3.12.2  yamt  * are met:
     12  1.3.12.2  yamt  * 1. Redistributions of source code must retain the above copyright
     13  1.3.12.2  yamt  *    notice, this list of conditions and the following disclaimer.
     14  1.3.12.2  yamt  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.3.12.2  yamt  *    notice, this list of conditions and the following disclaimer in the
     16  1.3.12.2  yamt  *    documentation and/or other materials provided with the distribution.
     17  1.3.12.2  yamt  * 3. The name of Itronix Inc. may not be used to endorse
     18  1.3.12.2  yamt  *    or promote products derived from this software without specific
     19  1.3.12.2  yamt  *    prior written permission.
     20  1.3.12.2  yamt  *
     21  1.3.12.2  yamt  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
     22  1.3.12.2  yamt  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     23  1.3.12.2  yamt  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  1.3.12.2  yamt  * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     25  1.3.12.2  yamt  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.3.12.2  yamt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     27  1.3.12.2  yamt  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  1.3.12.2  yamt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  1.3.12.2  yamt  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  1.3.12.2  yamt  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     31  1.3.12.2  yamt  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  1.3.12.2  yamt  */
     33  1.3.12.2  yamt 
     34  1.3.12.2  yamt #include <sys/cdefs.h>
     35  1.3.12.3  yamt __KERNEL_RCSID(0, "$NetBSD: edid.c,v 1.3.12.3 2007/09/03 14:39:29 yamt Exp $");
     36  1.3.12.2  yamt 
     37  1.3.12.2  yamt #include <sys/param.h>
     38  1.3.12.2  yamt #include <sys/systm.h>
     39  1.3.12.2  yamt #include <sys/device.h>
     40  1.3.12.2  yamt #include <sys/kernel.h>
     41  1.3.12.2  yamt #include <sys/malloc.h>
     42  1.3.12.2  yamt #include <dev/videomode/videomode.h>
     43  1.3.12.2  yamt #include <dev/videomode/ediddevs.h>
     44  1.3.12.2  yamt #include <dev/videomode/edidreg.h>
     45  1.3.12.2  yamt #include <dev/videomode/edidvar.h>
     46  1.3.12.2  yamt #include <dev/videomode/vesagtf.h>
     47  1.3.12.2  yamt 
     48  1.3.12.2  yamt #define	EDIDVERBOSE	1
     49  1.3.12.2  yamt #define	DIVIDE(x,y)	(((x) + ((y) / 2)) / (y))
     50  1.3.12.2  yamt 
     51  1.3.12.2  yamt static const char *_edid_modes[] =  {
     52  1.3.12.2  yamt 	"1280x1024x75",
     53  1.3.12.2  yamt 	"1024x768x75",
     54  1.3.12.2  yamt 	"1024x768x70",
     55  1.3.12.2  yamt 	"1024x768x60",
     56  1.3.12.2  yamt 	"1024x768x87i",
     57  1.3.12.2  yamt 	"832x768x74",	/* rounding error, 74.55 Hz aka "832x624x75" */
     58  1.3.12.2  yamt 	"800x600x75",
     59  1.3.12.2  yamt 	"800x600x72",
     60  1.3.12.2  yamt 	"800x600x60",
     61  1.3.12.2  yamt 	"800x600x56",
     62  1.3.12.2  yamt 	"640x480x75",
     63  1.3.12.2  yamt 	"640x480x72",
     64  1.3.12.2  yamt 	"640x480x67",
     65  1.3.12.2  yamt 	"640x480x60",
     66  1.3.12.2  yamt 	"720x400x85",	/* should this really be "720x400x88" ? */
     67  1.3.12.2  yamt 	"720x400x70",	/* hmm... videmode.c doesn't have this one */
     68  1.3.12.2  yamt };
     69  1.3.12.2  yamt 
     70  1.3.12.2  yamt #ifdef	EDIDVERBOSE
     71  1.3.12.2  yamt struct edid_vendor {
     72  1.3.12.2  yamt 	const char	*vendor;
     73  1.3.12.2  yamt 	const char	*name;
     74  1.3.12.2  yamt };
     75  1.3.12.2  yamt 
     76  1.3.12.2  yamt struct edid_product {
     77  1.3.12.2  yamt 	const char	*vendor;
     78  1.3.12.2  yamt 	uint16_t	product;
     79  1.3.12.2  yamt 	const char	*name;
     80  1.3.12.2  yamt };
     81  1.3.12.2  yamt 
     82  1.3.12.2  yamt #include <dev/videomode/ediddevs_data.h>
     83  1.3.12.2  yamt #endif	/* EDIDVERBOSE */
     84  1.3.12.2  yamt 
     85  1.3.12.2  yamt static const char *
     86  1.3.12.2  yamt edid_findvendor(const char *vendor)
     87  1.3.12.2  yamt {
     88  1.3.12.2  yamt #ifdef	EDIDVERBOSE
     89  1.3.12.2  yamt 	int	n;
     90  1.3.12.2  yamt 
     91  1.3.12.2  yamt 	for (n = 0; n < edid_nvendors; n++)
     92  1.3.12.2  yamt 		if (memcmp(edid_vendors[n].vendor, vendor, 3) == 0)
     93  1.3.12.2  yamt 			return (edid_vendors[n].name);
     94  1.3.12.2  yamt #endif
     95  1.3.12.2  yamt 	return NULL;
     96  1.3.12.2  yamt }
     97  1.3.12.2  yamt 
     98  1.3.12.2  yamt static const char *
     99  1.3.12.2  yamt edid_findproduct(const char *vendor, uint16_t product)
    100  1.3.12.2  yamt {
    101  1.3.12.2  yamt #ifdef	EDIDVERBOSE
    102  1.3.12.2  yamt 	int	n;
    103  1.3.12.2  yamt 
    104  1.3.12.2  yamt 	for (n = 0; n < edid_nvendors; n++)
    105  1.3.12.2  yamt 		if ((edid_products[n].product == product) &&
    106  1.3.12.2  yamt 		    (memcmp(edid_products[n].vendor, vendor, 3) == 0))
    107  1.3.12.2  yamt 			return (edid_products[n].name);
    108  1.3.12.2  yamt #endif	/* EDIDVERBOSE */
    109  1.3.12.2  yamt 	return NULL;
    110  1.3.12.2  yamt 
    111  1.3.12.2  yamt }
    112  1.3.12.2  yamt 
    113  1.3.12.2  yamt static void
    114  1.3.12.2  yamt edid_strchomp(char *ptr)
    115  1.3.12.2  yamt {
    116  1.3.12.2  yamt 	for (;;) {
    117  1.3.12.2  yamt 		switch (*ptr) {
    118  1.3.12.2  yamt 		case 0:
    119  1.3.12.2  yamt 			return;
    120  1.3.12.2  yamt 		case '\r':
    121  1.3.12.2  yamt 		case '\n':
    122  1.3.12.2  yamt 			*ptr = 0;
    123  1.3.12.2  yamt 			return;
    124  1.3.12.2  yamt 		}
    125  1.3.12.2  yamt 		ptr++;
    126  1.3.12.2  yamt 	}
    127  1.3.12.2  yamt }
    128  1.3.12.2  yamt 
    129  1.3.12.2  yamt int
    130  1.3.12.2  yamt edid_is_valid(uint8_t *d)
    131  1.3.12.2  yamt {
    132  1.3.12.2  yamt 	int sum = 0, i;
    133  1.3.12.2  yamt 	uint8_t sig[8] = EDID_SIGNATURE;
    134  1.3.12.2  yamt 
    135  1.3.12.2  yamt 	if (memcmp(d, sig, 8) != 0)
    136  1.3.12.2  yamt 		return EINVAL;
    137  1.3.12.2  yamt 
    138  1.3.12.2  yamt 	for (i = 0; i < 128; i++)
    139  1.3.12.2  yamt 		sum += d[i];
    140  1.3.12.2  yamt 	if ((sum & 0xff) != 0)
    141  1.3.12.2  yamt 		return EINVAL;
    142  1.3.12.2  yamt 
    143  1.3.12.2  yamt 	return 0;
    144  1.3.12.2  yamt }
    145  1.3.12.2  yamt 
    146  1.3.12.2  yamt void
    147  1.3.12.2  yamt edid_print(struct edid_info *edid)
    148  1.3.12.2  yamt {
    149  1.3.12.2  yamt 	int	i;
    150  1.3.12.2  yamt 
    151  1.3.12.2  yamt 	if (edid == NULL)
    152  1.3.12.2  yamt 		return;
    153  1.3.12.2  yamt 	printf("Vendor: [%s] %s\n", edid->edid_vendor, edid->edid_vendorname);
    154  1.3.12.2  yamt 	printf("Product: [%04X] %s\n", edid->edid_product,
    155  1.3.12.2  yamt 	    edid->edid_productname);
    156  1.3.12.2  yamt 	printf("Serial number: %s\n", edid->edid_serial);
    157  1.3.12.2  yamt 	printf("Manufactured %d Week %d\n",
    158  1.3.12.2  yamt 	    edid->edid_year, edid->edid_week);
    159  1.3.12.2  yamt 	printf("EDID Version %d.%d\n", edid->edid_version,
    160  1.3.12.2  yamt 	    edid->edid_revision);
    161  1.3.12.2  yamt 	printf("EDID Comment: %s\n", edid->edid_comment);
    162  1.3.12.2  yamt 
    163  1.3.12.2  yamt 	printf("Video Input: %x\n", edid->edid_video_input);
    164  1.3.12.2  yamt 	if (edid->edid_video_input & EDID_VIDEO_INPUT_DIGITAL) {
    165  1.3.12.2  yamt 		printf("\tDigital");
    166  1.3.12.2  yamt 		if (edid->edid_video_input & EDID_VIDEO_INPUT_DFP1_COMPAT)
    167  1.3.12.2  yamt 			printf(" (DFP 1.x compatible)");
    168  1.3.12.2  yamt 		printf("\n");
    169  1.3.12.2  yamt 	} else {
    170  1.3.12.2  yamt 		printf("\tAnalog\n");
    171  1.3.12.2  yamt 		switch (EDID_VIDEO_INPUT_LEVEL(edid->edid_video_input)) {
    172  1.3.12.2  yamt 		case 0:
    173  1.3.12.2  yamt 			printf("\t-0.7, 0.3V\n");
    174  1.3.12.2  yamt 			break;
    175  1.3.12.2  yamt 		case 1:
    176  1.3.12.2  yamt 			printf("\t-0.714, 0.286V\n");
    177  1.3.12.2  yamt 			break;
    178  1.3.12.2  yamt 		case 2:
    179  1.3.12.2  yamt 			printf("\t-1.0, 0.4V\n");
    180  1.3.12.2  yamt 			break;
    181  1.3.12.2  yamt 		case 3:
    182  1.3.12.2  yamt 			printf("\t-0.7, 0.0V\n");
    183  1.3.12.2  yamt 			break;
    184  1.3.12.2  yamt 		}
    185  1.3.12.2  yamt 		if (edid->edid_video_input & EDID_VIDEO_INPUT_BLANK_TO_BLACK)
    186  1.3.12.2  yamt 			printf("\tBlank-to-black setup\n");
    187  1.3.12.2  yamt 		if (edid->edid_video_input & EDID_VIDEO_INPUT_SEPARATE_SYNCS)
    188  1.3.12.2  yamt 			printf("\tSeperate syncs\n");
    189  1.3.12.2  yamt 		if (edid->edid_video_input & EDID_VIDEO_INPUT_COMPOSITE_SYNC)
    190  1.3.12.2  yamt 			printf("\tComposite sync\n");
    191  1.3.12.2  yamt 		if (edid->edid_video_input & EDID_VIDEO_INPUT_SYNC_ON_GRN)
    192  1.3.12.2  yamt 			printf("\tSync on green\n");
    193  1.3.12.2  yamt 		if (edid->edid_video_input & EDID_VIDEO_INPUT_SERRATION)
    194  1.3.12.2  yamt 			printf("\tSerration vsync\n");
    195  1.3.12.2  yamt 	}
    196  1.3.12.2  yamt 
    197  1.3.12.2  yamt 	printf("Gamma: %d.%02d\n",
    198  1.3.12.2  yamt 	    edid->edid_gamma / 100, edid->edid_gamma % 100);
    199  1.3.12.2  yamt 
    200  1.3.12.2  yamt 	printf("Max Size: %d cm x %d cm\n",
    201  1.3.12.2  yamt 	    edid->edid_max_hsize, edid->edid_max_vsize);
    202  1.3.12.2  yamt 
    203  1.3.12.2  yamt 	printf("Features: %x\n", edid->edid_features);
    204  1.3.12.2  yamt 	if (edid->edid_features & EDID_FEATURES_STANDBY)
    205  1.3.12.2  yamt 		printf("\tDPMS standby\n");
    206  1.3.12.2  yamt 	if (edid->edid_features & EDID_FEATURES_SUSPEND)
    207  1.3.12.2  yamt 		printf("\tDPMS suspend\n");
    208  1.3.12.2  yamt 	if (edid->edid_features & EDID_FEATURES_ACTIVE_OFF)
    209  1.3.12.2  yamt 		printf("\tDPMS active-off\n");
    210  1.3.12.2  yamt 	switch (EDID_FEATURES_DISP_TYPE(edid->edid_features)) {
    211  1.3.12.2  yamt 	case EDID_FEATURES_DISP_TYPE_MONO:
    212  1.3.12.2  yamt 		printf("\tMonochrome\n");
    213  1.3.12.2  yamt 		break;
    214  1.3.12.2  yamt 	case EDID_FEATURES_DISP_TYPE_RGB:
    215  1.3.12.2  yamt 		printf("\tRGB\n");
    216  1.3.12.2  yamt 		break;
    217  1.3.12.2  yamt 	case EDID_FEATURES_DISP_TYPE_NON_RGB:
    218  1.3.12.2  yamt 		printf("\tMulticolor\n");
    219  1.3.12.2  yamt 		break;
    220  1.3.12.2  yamt 	case EDID_FEATURES_DISP_TYPE_UNDEFINED:
    221  1.3.12.2  yamt 		printf("\tUndefined monitor type\n");
    222  1.3.12.2  yamt 		break;
    223  1.3.12.2  yamt 	}
    224  1.3.12.2  yamt 	if (edid->edid_features & EDID_FEATURES_STD_COLOR)
    225  1.3.12.2  yamt 		printf("\tStandard color space\n");
    226  1.3.12.2  yamt 	if (edid->edid_features & EDID_FEATURES_PREFERRED_TIMING)
    227  1.3.12.2  yamt 		printf("\tPreferred timing\n");
    228  1.3.12.2  yamt 	if (edid->edid_features & EDID_FEATURES_DEFAULT_GTF)
    229  1.3.12.2  yamt 		printf("\tDefault GTF supported\n");
    230  1.3.12.2  yamt 
    231  1.3.12.2  yamt 	printf("Chroma Info:\n");
    232  1.3.12.2  yamt 	printf("\tRed X: 0.%03d\n", edid->edid_chroma.ec_redx);
    233  1.3.12.2  yamt 	printf("\tRed Y: 0.%03d\n", edid->edid_chroma.ec_redy);
    234  1.3.12.2  yamt 	printf("\tGrn X: 0.%03d\n", edid->edid_chroma.ec_greenx);
    235  1.3.12.2  yamt 	printf("\tGrn Y: 0.%03d\n", edid->edid_chroma.ec_greeny);
    236  1.3.12.2  yamt 	printf("\tBlu X: 0.%03d\n", edid->edid_chroma.ec_bluex);
    237  1.3.12.2  yamt 	printf("\tBlu Y: 0.%03d\n", edid->edid_chroma.ec_bluey);
    238  1.3.12.2  yamt 	printf("\tWht X: 0.%03d\n", edid->edid_chroma.ec_whitex);
    239  1.3.12.2  yamt 	printf("\tWht Y: 0.%03d\n", edid->edid_chroma.ec_whitey);
    240  1.3.12.2  yamt 
    241  1.3.12.2  yamt 	if (edid->edid_have_range) {
    242  1.3.12.2  yamt 		printf("Range:\n");
    243  1.3.12.2  yamt 		printf("\tHorizontal: %d - %d kHz\n",
    244  1.3.12.2  yamt 		    edid->edid_range.er_min_hfreq,
    245  1.3.12.2  yamt 		    edid->edid_range.er_max_hfreq);
    246  1.3.12.2  yamt 		printf("\tVertical: %d - %d Hz\n",
    247  1.3.12.2  yamt 		    edid->edid_range.er_min_vfreq,
    248  1.3.12.2  yamt 		    edid->edid_range.er_max_vfreq);
    249  1.3.12.2  yamt 		printf("\tMax Dot Clock: %d MHz\n",
    250  1.3.12.2  yamt 		    edid->edid_range.er_max_clock);
    251  1.3.12.2  yamt 		if (edid->edid_range.er_have_gtf2) {
    252  1.3.12.2  yamt 			printf("\tGTF2 hfreq: %d\n",
    253  1.3.12.2  yamt 			    edid->edid_range.er_gtf2_hfreq);
    254  1.3.12.2  yamt 			printf("\tGTF2 C: %d\n", edid->edid_range.er_gtf2_c);
    255  1.3.12.2  yamt 			printf("\tGTF2 M: %d\n", edid->edid_range.er_gtf2_m);
    256  1.3.12.2  yamt 			printf("\tGTF2 J: %d\n", edid->edid_range.er_gtf2_j);
    257  1.3.12.2  yamt 			printf("\tGTF2 K: %d\n", edid->edid_range.er_gtf2_k);
    258  1.3.12.2  yamt 		}
    259  1.3.12.2  yamt 	}
    260  1.3.12.2  yamt 	printf("Video modes:\n");
    261  1.3.12.2  yamt 	for (i = 0; i < edid->edid_nmodes; i++) {
    262  1.3.12.2  yamt 		printf("\t%dx%d @ %dHz\n",
    263  1.3.12.2  yamt 		    edid->edid_modes[i].hdisplay,
    264  1.3.12.2  yamt 		    edid->edid_modes[i].vdisplay,
    265  1.3.12.2  yamt 		    DIVIDE(DIVIDE(edid->edid_modes[i].dot_clock * 1000,
    266  1.3.12.2  yamt 			       edid->edid_modes[i].htotal),
    267  1.3.12.2  yamt 			edid->edid_modes[i].vtotal));
    268  1.3.12.2  yamt 	}
    269  1.3.12.2  yamt 	if (edid->edid_preferred_mode)
    270  1.3.12.2  yamt 		printf("Preferred mode: %dx%d @ %dHz\n",
    271  1.3.12.2  yamt 		    edid->edid_preferred_mode->hdisplay,
    272  1.3.12.2  yamt 		    edid->edid_preferred_mode->vdisplay,
    273  1.3.12.2  yamt 		    DIVIDE(DIVIDE(edid->edid_preferred_mode->dot_clock * 1000,
    274  1.3.12.2  yamt 			       edid->edid_preferred_mode->htotal),
    275  1.3.12.2  yamt 			edid->edid_preferred_mode->vtotal));
    276  1.3.12.2  yamt }
    277  1.3.12.2  yamt 
    278  1.3.12.2  yamt static const struct videomode *
    279  1.3.12.2  yamt edid_mode_lookup_list(const char *name)
    280  1.3.12.2  yamt {
    281  1.3.12.2  yamt 	int	i;
    282  1.3.12.2  yamt 
    283  1.3.12.2  yamt 	for (i = 0; i < videomode_count; i++)
    284  1.3.12.2  yamt 		if (strcmp(name, videomode_list[i].name) == 0)
    285  1.3.12.2  yamt 			return &videomode_list[i];
    286  1.3.12.2  yamt 	return NULL;
    287  1.3.12.2  yamt }
    288  1.3.12.2  yamt 
    289  1.3.12.2  yamt static int
    290  1.3.12.2  yamt edid_std_timing(uint8_t *data, struct videomode *vmp)
    291  1.3.12.2  yamt {
    292  1.3.12.2  yamt 	unsigned			x, y, f;
    293  1.3.12.2  yamt 	const struct videomode		*lookup;
    294  1.3.12.2  yamt 	char				name[80];
    295  1.3.12.2  yamt 
    296  1.3.12.2  yamt 	if ((data[0] == 1 && data[1] == 1) ||
    297  1.3.12.2  yamt 	    (data[0] == 0 && data[1] == 0) ||
    298  1.3.12.2  yamt 	    (data[0] == 0x20 && data[1] == 0x20))
    299  1.3.12.2  yamt 		return 0;
    300  1.3.12.2  yamt 
    301  1.3.12.2  yamt 	x = EDID_STD_TIMING_HRES(data);
    302  1.3.12.2  yamt 	switch (EDID_STD_TIMING_RATIO(data)) {
    303  1.3.12.2  yamt 	case EDID_STD_TIMING_RATIO_16_10:
    304  1.3.12.2  yamt 		y = x * 10 / 16;
    305  1.3.12.2  yamt 		break;
    306  1.3.12.2  yamt 	case EDID_STD_TIMING_RATIO_4_3:
    307  1.3.12.2  yamt 		y = x * 3 / 4;
    308  1.3.12.2  yamt 		break;
    309  1.3.12.2  yamt 	case EDID_STD_TIMING_RATIO_5_4:
    310  1.3.12.2  yamt 		y = x * 4 / 5;
    311  1.3.12.2  yamt 		break;
    312  1.3.12.2  yamt 	case EDID_STD_TIMING_RATIO_16_9:
    313  1.3.12.2  yamt 	default:
    314  1.3.12.2  yamt 		y = x * 9 / 16;
    315  1.3.12.2  yamt 		break;
    316  1.3.12.2  yamt 	}
    317  1.3.12.2  yamt 	f = EDID_STD_TIMING_VFREQ(data);
    318  1.3.12.2  yamt 
    319  1.3.12.2  yamt 	/* first try to lookup the mode as a DMT timing */
    320  1.3.12.2  yamt 	snprintf(name, sizeof (name), "%dx%dx%d", x, y, f);
    321  1.3.12.2  yamt 	if ((lookup = edid_mode_lookup_list(name)) != NULL) {
    322  1.3.12.2  yamt 		*vmp = *lookup;
    323  1.3.12.2  yamt 	}
    324  1.3.12.2  yamt 
    325  1.3.12.2  yamt 	/* failing that, calculate it using gtf */
    326  1.3.12.2  yamt 	else {
    327  1.3.12.2  yamt 		/*
    328  1.3.12.2  yamt 		 * Hmm. I'm not using alternate GTF timings, which
    329  1.3.12.2  yamt 		 * could, in theory, be present.
    330  1.3.12.2  yamt 		 */
    331  1.3.12.2  yamt 		vesagtf_mode(x, y, f, vmp);
    332  1.3.12.2  yamt 	}
    333  1.3.12.2  yamt 	return 1;
    334  1.3.12.2  yamt }
    335  1.3.12.2  yamt 
    336  1.3.12.2  yamt static int
    337  1.3.12.2  yamt edid_det_timing(uint8_t *data, struct videomode *vmp)
    338  1.3.12.2  yamt {
    339  1.3.12.2  yamt 	unsigned	hactive, hblank, hsyncwid, hsyncoff;
    340  1.3.12.2  yamt 	unsigned	vactive, vblank, vsyncwid, vsyncoff;
    341  1.3.12.2  yamt 	uint8_t		flags;
    342  1.3.12.2  yamt 
    343  1.3.12.2  yamt 	flags = EDID_DET_TIMING_FLAGS(data);
    344  1.3.12.2  yamt 
    345  1.3.12.2  yamt 	/* we don't support stereo modes (for now) */
    346  1.3.12.2  yamt 	if (flags & (EDID_DET_TIMING_FLAG_STEREO |
    347  1.3.12.2  yamt 		EDID_DET_TIMING_FLAG_STEREO1))
    348  1.3.12.2  yamt 		return 0;
    349  1.3.12.2  yamt 
    350  1.3.12.2  yamt 	vmp->dot_clock = EDID_DET_TIMING_DOT_CLOCK(data) / 1000;
    351  1.3.12.2  yamt 
    352  1.3.12.2  yamt 	hactive = EDID_DET_TIMING_HACTIVE(data);
    353  1.3.12.2  yamt 	hblank = EDID_DET_TIMING_HBLANK(data);
    354  1.3.12.2  yamt 	hsyncwid = EDID_DET_TIMING_HSYNC_WIDTH(data);
    355  1.3.12.2  yamt 	hsyncoff = EDID_DET_TIMING_HSYNC_OFFSET(data);
    356  1.3.12.2  yamt 
    357  1.3.12.2  yamt 	vactive = EDID_DET_TIMING_VACTIVE(data);
    358  1.3.12.2  yamt 	vblank = EDID_DET_TIMING_VBLANK(data);
    359  1.3.12.2  yamt 	vsyncwid = EDID_DET_TIMING_VSYNC_WIDTH(data);
    360  1.3.12.2  yamt 	vsyncoff = EDID_DET_TIMING_VSYNC_OFFSET(data);
    361  1.3.12.2  yamt 
    362  1.3.12.2  yamt 	/* XXX: I'm not doing anything with the borders, should I? */
    363  1.3.12.2  yamt 
    364  1.3.12.2  yamt 	vmp->hdisplay = hactive;
    365  1.3.12.2  yamt 	vmp->htotal = hactive + hblank;
    366  1.3.12.2  yamt 	vmp->hsync_start = hactive + hsyncoff;
    367  1.3.12.2  yamt 	vmp->hsync_end = vmp->hsync_start + hsyncwid;
    368  1.3.12.2  yamt 
    369  1.3.12.2  yamt 	vmp->vdisplay = vactive;
    370  1.3.12.2  yamt 	vmp->vtotal = vactive + vblank;
    371  1.3.12.2  yamt 	vmp->vsync_start = vactive + vsyncoff;
    372  1.3.12.2  yamt 	vmp->vsync_end = vmp->vsync_start + vsyncwid;
    373  1.3.12.2  yamt 
    374  1.3.12.2  yamt 	vmp->flags = 0;
    375  1.3.12.2  yamt 
    376  1.3.12.2  yamt 	if (flags & EDID_DET_TIMING_FLAG_INTERLACE)
    377  1.3.12.2  yamt 		vmp->flags |= VID_INTERLACE;
    378  1.3.12.2  yamt 	if (flags & EDID_DET_TIMING_FLAG_HSYNC_POSITIVE)
    379  1.3.12.2  yamt 		vmp->flags |= VID_PHSYNC;
    380  1.3.12.2  yamt 	else
    381  1.3.12.2  yamt 		vmp->flags |= VID_NHSYNC;
    382  1.3.12.2  yamt 
    383  1.3.12.2  yamt 	if (flags & EDID_DET_TIMING_FLAG_VSYNC_POSITIVE)
    384  1.3.12.2  yamt 		vmp->flags |= VID_PVSYNC;
    385  1.3.12.2  yamt 	else
    386  1.3.12.2  yamt 		vmp->flags |= VID_NVSYNC;
    387  1.3.12.2  yamt 
    388  1.3.12.2  yamt 	return 1;
    389  1.3.12.2  yamt }
    390  1.3.12.2  yamt 
    391  1.3.12.2  yamt static void
    392  1.3.12.2  yamt edid_block(struct edid_info *edid, uint8_t *data)
    393  1.3.12.2  yamt {
    394  1.3.12.2  yamt 	int			i;
    395  1.3.12.2  yamt 	struct videomode	mode;
    396  1.3.12.2  yamt 
    397  1.3.12.2  yamt 	if (EDID_BLOCK_IS_DET_TIMING(data)) {
    398  1.3.12.2  yamt 		if (edid_det_timing(data, &mode)) {
    399  1.3.12.2  yamt 			edid->edid_modes[edid->edid_nmodes] = mode;
    400  1.3.12.2  yamt 			if (edid->edid_preferred_mode == NULL) {
    401  1.3.12.2  yamt 				edid->edid_preferred_mode =
    402  1.3.12.2  yamt 				    &edid->edid_modes[edid->edid_nmodes];
    403  1.3.12.2  yamt 			}
    404  1.3.12.2  yamt 			edid->edid_nmodes++;
    405  1.3.12.2  yamt 		}
    406  1.3.12.2  yamt 		return;
    407  1.3.12.2  yamt 	}
    408  1.3.12.2  yamt 
    409  1.3.12.2  yamt 	switch (EDID_BLOCK_TYPE(data)) {
    410  1.3.12.2  yamt 	case EDID_DESC_BLOCK_TYPE_SERIAL:
    411  1.3.12.2  yamt 		memcpy(edid->edid_serial,
    412  1.3.12.2  yamt 		    data + EDID_DESC_ASCII_DATA_OFFSET,
    413  1.3.12.2  yamt 		    EDID_DESC_ASCII_DATA_LEN);
    414  1.3.12.2  yamt 		edid->edid_serial[sizeof (edid->edid_serial) - 1] = 0;
    415  1.3.12.2  yamt 		break;
    416  1.3.12.2  yamt 
    417  1.3.12.2  yamt 	case EDID_DESC_BLOCK_TYPE_ASCII:
    418  1.3.12.2  yamt 		memcpy(edid->edid_comment,
    419  1.3.12.2  yamt 		    data + EDID_DESC_ASCII_DATA_OFFSET,
    420  1.3.12.2  yamt 		    EDID_DESC_ASCII_DATA_LEN);
    421  1.3.12.2  yamt 		edid->edid_comment[sizeof (edid->edid_comment) - 1] = 0;
    422  1.3.12.2  yamt 		break;
    423  1.3.12.2  yamt 
    424  1.3.12.2  yamt 	case EDID_DESC_BLOCK_TYPE_RANGE:
    425  1.3.12.2  yamt 		edid->edid_have_range = 1;
    426  1.3.12.2  yamt 		edid->edid_range.er_min_vfreq =
    427  1.3.12.2  yamt 		    EDID_DESC_RANGE_MIN_VFREQ(data);
    428  1.3.12.2  yamt 		edid->edid_range.er_max_vfreq =
    429  1.3.12.2  yamt 		    EDID_DESC_RANGE_MAX_VFREQ(data);
    430  1.3.12.2  yamt 		edid->edid_range.er_min_hfreq =
    431  1.3.12.2  yamt 		    EDID_DESC_RANGE_MIN_HFREQ(data);
    432  1.3.12.2  yamt 		edid->edid_range.er_max_hfreq =
    433  1.3.12.2  yamt 		    EDID_DESC_RANGE_MAX_HFREQ(data);
    434  1.3.12.2  yamt 		edid->edid_range.er_max_clock =
    435  1.3.12.2  yamt 		    EDID_DESC_RANGE_MAX_CLOCK(data);
    436  1.3.12.2  yamt 		if (EDID_DESC_RANGE_HAVE_GTF2(data)) {
    437  1.3.12.2  yamt 			edid->edid_range.er_have_gtf2 = 1;
    438  1.3.12.2  yamt 			edid->edid_range.er_gtf2_hfreq =
    439  1.3.12.2  yamt 			    EDID_DESC_RANGE_GTF2_HFREQ(data);
    440  1.3.12.2  yamt 			edid->edid_range.er_gtf2_c =
    441  1.3.12.2  yamt 			    EDID_DESC_RANGE_GTF2_C(data);
    442  1.3.12.2  yamt 			edid->edid_range.er_gtf2_m =
    443  1.3.12.2  yamt 			    EDID_DESC_RANGE_GTF2_M(data);
    444  1.3.12.2  yamt 			edid->edid_range.er_gtf2_j =
    445  1.3.12.2  yamt 			    EDID_DESC_RANGE_GTF2_J(data);
    446  1.3.12.2  yamt 			edid->edid_range.er_gtf2_k =
    447  1.3.12.2  yamt 			    EDID_DESC_RANGE_GTF2_K(data);
    448  1.3.12.2  yamt 		}
    449  1.3.12.2  yamt 		break;
    450  1.3.12.2  yamt 
    451  1.3.12.2  yamt 	case EDID_DESC_BLOCK_TYPE_NAME:
    452  1.3.12.2  yamt 		/* copy the product name into place */
    453  1.3.12.2  yamt 		memcpy(edid->edid_productname,
    454  1.3.12.2  yamt 		    data + EDID_DESC_ASCII_DATA_OFFSET,
    455  1.3.12.2  yamt 		    EDID_DESC_ASCII_DATA_LEN);
    456  1.3.12.2  yamt 		break;
    457  1.3.12.2  yamt 
    458  1.3.12.2  yamt 	case EDID_DESC_BLOCK_TYPE_STD_TIMING:
    459  1.3.12.2  yamt 		data += EDID_DESC_STD_TIMING_START;
    460  1.3.12.2  yamt 		for (i = 0; i < EDID_DESC_STD_TIMING_COUNT; i++) {
    461  1.3.12.2  yamt 			if (edid_std_timing(data, &mode)) {
    462  1.3.12.2  yamt 				edid->edid_modes[edid->edid_nmodes] = mode;
    463  1.3.12.2  yamt 				edid->edid_nmodes++;
    464  1.3.12.2  yamt 			}
    465  1.3.12.2  yamt 			data += 2;
    466  1.3.12.2  yamt 		}
    467  1.3.12.2  yamt 		break;
    468  1.3.12.2  yamt 
    469  1.3.12.2  yamt 	case EDID_DESC_BLOCK_TYPE_COLOR_POINT:
    470  1.3.12.2  yamt 		/* XXX: not implemented yet */
    471  1.3.12.2  yamt 		break;
    472  1.3.12.2  yamt 	}
    473  1.3.12.2  yamt }
    474  1.3.12.2  yamt 
    475  1.3.12.2  yamt /*
    476  1.3.12.2  yamt  * Gets EDID version in BCD, e.g. EDID v1.3  returned as 0x0103
    477  1.3.12.2  yamt  */
    478  1.3.12.2  yamt int
    479  1.3.12.2  yamt edid_parse(uint8_t *data, struct edid_info *edid)
    480  1.3.12.2  yamt {
    481  1.3.12.2  yamt 	uint16_t		manfid, estmodes;
    482  1.3.12.2  yamt 	const struct videomode	*vmp;
    483  1.3.12.2  yamt 	int			i;
    484  1.3.12.2  yamt 	const char		*name;
    485  1.3.12.3  yamt 	int max_dotclock = 0;
    486  1.3.12.3  yamt 	int mhz;
    487  1.3.12.2  yamt 
    488  1.3.12.2  yamt 	if (edid_is_valid(data) != 0)
    489  1.3.12.2  yamt 		return -1;
    490  1.3.12.2  yamt 
    491  1.3.12.2  yamt 	/* get product identification */
    492  1.3.12.2  yamt 	manfid = EDID_VENDOR_ID(data);
    493  1.3.12.2  yamt 	edid->edid_vendor[0] = EDID_MANFID_0(manfid);
    494  1.3.12.2  yamt 	edid->edid_vendor[1] = EDID_MANFID_1(manfid);
    495  1.3.12.2  yamt 	edid->edid_vendor[2] = EDID_MANFID_2(manfid);
    496  1.3.12.2  yamt 	edid->edid_vendor[3] = 0;	/* null terminate for convenience */
    497  1.3.12.2  yamt 
    498  1.3.12.2  yamt 	edid->edid_product = data[EDID_OFFSET_PRODUCT_ID] +
    499  1.3.12.2  yamt 	    (data[EDID_OFFSET_PRODUCT_ID + 1] << 8);
    500  1.3.12.2  yamt 
    501  1.3.12.2  yamt 	name = edid_findvendor(edid->edid_vendor);
    502  1.3.12.2  yamt 	if (name != NULL) {
    503  1.3.12.2  yamt 		snprintf(edid->edid_vendorname,
    504  1.3.12.2  yamt 		    sizeof (edid->edid_vendorname), "%s", name);
    505  1.3.12.2  yamt 	}
    506  1.3.12.2  yamt 	edid->edid_vendorname[sizeof (edid->edid_vendorname) - 1] = 0;
    507  1.3.12.2  yamt 
    508  1.3.12.2  yamt 	name = edid_findproduct(edid->edid_vendor, edid->edid_product);
    509  1.3.12.2  yamt 	if (name != NULL) {
    510  1.3.12.2  yamt 		snprintf(edid->edid_productname,
    511  1.3.12.2  yamt 		    sizeof (edid->edid_productname), "%s", name);
    512  1.3.12.2  yamt 	}
    513  1.3.12.2  yamt 	edid->edid_productname[sizeof (edid->edid_productname) - 1] = 0;
    514  1.3.12.2  yamt 
    515  1.3.12.2  yamt 	snprintf(edid->edid_serial, sizeof (edid->edid_serial), "%08x",
    516  1.3.12.2  yamt 	    EDID_SERIAL_NUMBER(data));
    517  1.3.12.2  yamt 
    518  1.3.12.2  yamt 	edid->edid_week = EDID_WEEK(data);
    519  1.3.12.2  yamt 	edid->edid_year = EDID_YEAR(data);
    520  1.3.12.2  yamt 
    521  1.3.12.2  yamt 	/* get edid revision */
    522  1.3.12.2  yamt 	edid->edid_version = EDID_VERSION(data);
    523  1.3.12.2  yamt 	edid->edid_revision = EDID_REVISION(data);
    524  1.3.12.2  yamt 
    525  1.3.12.2  yamt 	edid->edid_video_input = EDID_VIDEO_INPUT(data);
    526  1.3.12.2  yamt 	edid->edid_max_hsize = EDID_MAX_HSIZE(data);
    527  1.3.12.2  yamt 	edid->edid_max_vsize = EDID_MAX_VSIZE(data);
    528  1.3.12.2  yamt 
    529  1.3.12.2  yamt 	edid->edid_gamma = EDID_GAMMA(data);
    530  1.3.12.2  yamt 	edid->edid_features = EDID_FEATURES(data);
    531  1.3.12.2  yamt 
    532  1.3.12.2  yamt 	edid->edid_chroma.ec_redx = EDID_CHROMA_REDX(data);
    533  1.3.12.2  yamt 	edid->edid_chroma.ec_redy = EDID_CHROMA_REDX(data);
    534  1.3.12.2  yamt 	edid->edid_chroma.ec_greenx = EDID_CHROMA_GREENX(data);
    535  1.3.12.2  yamt 	edid->edid_chroma.ec_greeny = EDID_CHROMA_GREENY(data);
    536  1.3.12.2  yamt 	edid->edid_chroma.ec_bluex = EDID_CHROMA_BLUEX(data);
    537  1.3.12.2  yamt 	edid->edid_chroma.ec_bluey = EDID_CHROMA_BLUEY(data);
    538  1.3.12.2  yamt 	edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITEX(data);
    539  1.3.12.2  yamt 	edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITEY(data);
    540  1.3.12.2  yamt 
    541  1.3.12.2  yamt 	/* lookup established modes */
    542  1.3.12.3  yamt 	edid->edid_nmodes = 0;
    543  1.3.12.3  yamt 	edid->edid_preferred_mode = NULL;
    544  1.3.12.2  yamt 	estmodes = EDID_EST_TIMING(data);
    545  1.3.12.2  yamt 	for (i = 0; i < 16; i++) {
    546  1.3.12.2  yamt 		if (estmodes & (1 << i)) {
    547  1.3.12.2  yamt 			vmp = edid_mode_lookup_list(_edid_modes[i]);
    548  1.3.12.2  yamt 			if (vmp != NULL) {
    549  1.3.12.2  yamt 				edid->edid_modes[edid->edid_nmodes] = *vmp;
    550  1.3.12.2  yamt 				edid->edid_nmodes++;
    551  1.3.12.2  yamt 			}
    552  1.3.12.3  yamt #ifdef DIAGNOSTIC
    553  1.3.12.3  yamt 			  else
    554  1.3.12.3  yamt 				printf("no data for est. mode %s\n",
    555  1.3.12.3  yamt 				    _edid_modes[i]);
    556  1.3.12.3  yamt #endif
    557  1.3.12.2  yamt 		}
    558  1.3.12.2  yamt 	}
    559  1.3.12.2  yamt 
    560  1.3.12.2  yamt 	/* do standard timing section */
    561  1.3.12.2  yamt 	for (i = 0; i < EDID_STD_TIMING_COUNT; i++) {
    562  1.3.12.2  yamt 		struct videomode	mode;
    563  1.3.12.2  yamt 		if (edid_std_timing(data + EDID_OFFSET_STD_TIMING + i * 2,
    564  1.3.12.2  yamt 			&mode)) {
    565  1.3.12.2  yamt 			edid->edid_modes[edid->edid_nmodes] = mode;
    566  1.3.12.2  yamt 			edid->edid_nmodes++;
    567  1.3.12.2  yamt 		}
    568  1.3.12.2  yamt 	}
    569  1.3.12.2  yamt 
    570  1.3.12.2  yamt 	/* do detailed timings and descriptors */
    571  1.3.12.2  yamt 	for (i = 0; i < EDID_BLOCK_COUNT; i++) {
    572  1.3.12.2  yamt 		edid_block(edid, data + EDID_OFFSET_DESC_BLOCK +
    573  1.3.12.2  yamt 		    i * EDID_BLOCK_SIZE);
    574  1.3.12.2  yamt 	}
    575  1.3.12.2  yamt 
    576  1.3.12.2  yamt 	edid_strchomp(edid->edid_vendorname);
    577  1.3.12.2  yamt 	edid_strchomp(edid->edid_productname);
    578  1.3.12.2  yamt 	edid_strchomp(edid->edid_serial);
    579  1.3.12.2  yamt 	edid_strchomp(edid->edid_comment);
    580  1.3.12.2  yamt 
    581  1.3.12.3  yamt 	/*
    582  1.3.12.3  yamt 	 * XXX
    583  1.3.12.3  yamt 	 * some monitors lie about their maximum supported dot clock
    584  1.3.12.3  yamt 	 * by claiming to support modes which need a higher dot clock
    585  1.3.12.3  yamt 	 * than the stated maximum.
    586  1.3.12.3  yamt 	 * For sanity's sake we bump it to the highest dot clock we find
    587  1.3.12.3  yamt 	 * in the list of supported modes
    588  1.3.12.3  yamt 	 */
    589  1.3.12.3  yamt 	for (i = 0; i < edid->edid_nmodes; i++)
    590  1.3.12.3  yamt 		if (edid->edid_modes[i].dot_clock > max_dotclock)
    591  1.3.12.3  yamt 			max_dotclock = edid->edid_modes[i].dot_clock;
    592  1.3.12.3  yamt 
    593  1.3.12.3  yamt 	aprint_verbose("max_dotclock according to supported modes: %d\n",
    594  1.3.12.3  yamt 	    max_dotclock);
    595  1.3.12.3  yamt 
    596  1.3.12.3  yamt 	mhz = (max_dotclock + 999) / 1000;
    597  1.3.12.3  yamt 
    598  1.3.12.3  yamt 	if (edid->edid_have_range) {
    599  1.3.12.3  yamt 
    600  1.3.12.3  yamt 		if (mhz > edid->edid_range.er_max_clock)
    601  1.3.12.3  yamt 			edid->edid_range.er_max_clock = mhz;
    602  1.3.12.3  yamt 	} else
    603  1.3.12.3  yamt 		edid->edid_range.er_max_clock = mhz;
    604  1.3.12.3  yamt 
    605  1.3.12.2  yamt 	return 0;
    606  1.3.12.2  yamt }
    607  1.3.12.2  yamt 
    608