From: Thomas Cort Date: Mon, 29 Jul 2013 16:21:48 +0000 (-0400) Subject: Importing sys/dev/videomode X-Git-Tag: v3.3.0~847 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zlib_tech.html?a=commitdiff_plain;h=refs%2Fchanges%2F33%2F733%2F2;p=minix.git Importing sys/dev/videomode NetBSD provides an in-kernel EDID parser, validator, and printer along with other useful functions. This code will be re-used by the Minix fb driver as it is a complete and well tested implementation. Change-Id: I46fe3005d9957cd90d4972030ddcce7bc3bd7924 --- diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index dc6889d7f..d4cf29b20 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -109,6 +109,7 @@ 2013/04/23 12:00:00,sys/dev/Makefile 2013/04/23 12:00:00,sys/dev/i2c/Makefile 2013/04/23 12:00:00,sys/dev/i2c/i2c_io.h +2013/07/22 12:00:00,sys/dev/videomode 2012/01/16 18:47:57,sys/lib/libsa 2012/10/17 12:00:00,sys/lib/libz 2012/10/17 12:00:00,sys/Makefile diff --git a/sys/dev/videomode/Makefile.ediddevs b/sys/dev/videomode/Makefile.ediddevs new file mode 100644 index 000000000..1680f71fa --- /dev/null +++ b/sys/dev/videomode/Makefile.ediddevs @@ -0,0 +1,15 @@ +# $NetBSD: Makefile.ediddevs,v 1.2 2008/10/19 22:05:23 apb Exp $ +# +# As per tron@NetBSD.org, the proper procedure is +# +# 1.) Change "src/sys/dev/videomode/ediddevs". +# 2.) Commit "src/sys/dev/videomode/ediddevs". +# 3.) Execute "make -f Makefile.ediddevs" in "src/sys/dev/videomode". +# 4.) Commit "src/sys/dev/videomode/ediddevs.h" and +# "src/sys/dev/videomode/ediddevs_data.h". + +.include + +ediddevs.h ediddevs_data.h: ediddevs devlist2h.awk + /bin/rm -f ediddevs.h ediddevs_data.h + ${TOOL_AWK} -f devlist2h.awk ediddevs diff --git a/sys/dev/videomode/Makefile.videomode b/sys/dev/videomode/Makefile.videomode new file mode 100644 index 000000000..b9b10aa55 --- /dev/null +++ b/sys/dev/videomode/Makefile.videomode @@ -0,0 +1,17 @@ +# $NetBSD: Makefile.videomode,v 1.2 2008/10/19 22:05:23 apb Exp $ +# +# As per tron@NetBSD.org, the proper procedure is +# +# 1.) Change "src/sys/dev/videomode/modelines". +# 2.) Commit "src/sys/dev/videomode/modelines". +# 3.) Execute "make -f Makefile.videomode" in "src/sys/dev/videomode". +# 4.) Commit "src/sys/dev/videomode/videomode.c" + +.include + +videomode.c: modelines modelines2c.awk + /bin/rm -f videomode.c + ${TOOL_AWK} -f modelines2c.awk modelines > videomode.c + +test: videomode.c videomode.h test.c + ${CC} -I ../../ -o test test.c videomode.c diff --git a/sys/dev/videomode/devlist2h.awk b/sys/dev/videomode/devlist2h.awk new file mode 100644 index 000000000..987da303c --- /dev/null +++ b/sys/dev/videomode/devlist2h.awk @@ -0,0 +1,192 @@ +#! /usr/bin/awk -f +# $NetBSD: devlist2h.awk,v 1.1 2006/05/11 01:49:53 gdamore Exp $ +# +# Copyright (c) 1995, 1996 Christopher G. Demetriou +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Christopher G. Demetriou. +# 4. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +BEGIN { + nproducts = nvendors = blanklines = 0 + dfile="ediddevs_data.h" + hfile="ediddevs.h" +} +NR == 1 { + VERSION = $0 + gsub("\\$", "", VERSION) + gsub(/ $/, "", VERSION) + + printf("/*\t$NetBSD" "$\t*/\n\n") > dfile + printf("/*\n") > dfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > dfile + printf(" *\n") > dfile + printf(" * generated from:\n") > dfile + printf(" *\t%s\n", VERSION) > dfile + printf(" */\n") > dfile + + printf("/*\t$NetBSD" "$\t*/\n\n") > hfile + printf("/*\n") > hfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > hfile + printf(" *\n") > hfile + printf(" * generated from:\n") > hfile + printf(" *\t%s\n", VERSION) > hfile + printf(" */\n") > hfile + + next +} + +NF > 0 && $1 == "vendor" { + nvendors++ + + vendorindex[$2] = nvendors; # record index for this name, for later. + vendors[nvendors, 1] = $2; # name/ID + i = 2; f = 3; + + printf("#define\tEDID_VENDOR_%s\t\"", vendors[nvendors, 1]) > hfile + + # comments + oparen = 0 + while (f <= NF) { + if ($f == "#") { + printf("(") > hfile + oparen = 1 + f++ + continue + } + if (oparen) { + printf("%s", $f) > hfile + f++ + continue + } + vendors[nvendors, i] = $f + printf("%s", vendors[nvendors, i]) > hfile + if (f < NF) + printf(" ") > hfile + i++; f++; + } + if (oparen) + printf(")") > hfile + printf("\"") > hfile + printf("\n") > hfile + + next +} + +NF > 0 && $1 == "product" { + nproducts++ + + products[nproducts, 1] = $2; # vendor name + products[nproducts, 2] = $3; # product id + products[nproducts, 3] = $4; # id + printf("#define\tEDID_PRODUCT_%s_%s\t%s", products[nproducts, 1], + products[nproducts, 2], products[nproducts, 3]) > hfile + + i = 4; f = 5; + + ocomment = oparen = 0 + if (f <= NF) { + printf("\t\t/* ") > hfile + ocomment = 1; + } + while (f <= NF) { + if ($f == "#") { + printf("(") > hfile + oparen = 1 + f++ + continue + } + if (oparen) { + printf("%s", $f) > hfile + if (f < NF) + printf(" ") > hfile + f++ + continue + } + products[nproducts, i] = $f + printf("%s", products[nproducts, i]) > hfile + if (f < NF) + printf(" ") > hfile + i++; f++; + } + if (oparen) + printf(")") > hfile + if (ocomment) + printf(" */") > hfile + printf("\n") > hfile + + next +} +{ + if ($0 == "") + blanklines++ + if (blanklines != 2 && blanklines != 3) + print $0 > hfile + if (blanklines < 2) + print $0 > dfile +} +END { + # print out the match tables + + printf("\n") > dfile + printf("const struct edid_vendor edid_vendors[] = {\n") > dfile + + for (i = 1; i <= nvendors; i++) { + printf("\t{") > dfile + printf(" \"%s\", EDID_VENDOR_%s", vendors[i, 1], \ + vendors[i, 1]) > dfile + printf(" },\n") > dfile + } + printf("};\n") > dfile + printf("const int edid_nvendors = %d;\n", nvendors) > dfile + + printf("\n") > dfile + + printf("const struct edid_product edid_products[] = {\n") > dfile + for (i = 1; i <= nproducts; i++) { + printf("\t{\n") > dfile + printf("\t \"%s\", EDID_PRODUCT_%s_%s,\n", \ + products[i, 1], products[i, 1], products[i, 2]) > dfile + printf("\t \"") > dfile + j = 4 + needspace = 0 + while ((i, j) in products) { + if (needspace) + printf(" ") > dfile + printf("%s", products[i, j]) > dfile + needspace = 1 + j++ + } + printf("\",\n") > dfile + printf("\t},\n") > dfile + } + printf("};\n") > dfile + printf("const int edid_nproducts = %d;\n", nproducts) >dfile + + close(dfile) + close(hfile) +} diff --git a/sys/dev/videomode/edid.c b/sys/dev/videomode/edid.c new file mode 100644 index 000000000..c963b4f5f --- /dev/null +++ b/sys/dev/videomode/edid.c @@ -0,0 +1,651 @@ +/* $NetBSD: edid.c,v 1.12 2013/02/08 16:35:10 skrll Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: edid.c,v 1.12 2013/02/08 16:35:10 skrll Exp $"); + +#include +#ifdef __minix +#include +#include +#include +#ifndef aprint_debug +#define aprint_debug if (0) printf +#endif /* !aprint_debug */ +#else /* !__minix */ +#include +#include +#include +#include +#endif /* !__minix */ +#include +#include +#include +#include +#include + +#define EDIDVERBOSE 1 +#define DIVIDE(x,y) (((x) + ((y) / 2)) / (y)) + +/* These are reversed established timing order */ +static const char *_edid_modes[] = { + "1280x1024x75", + "1024x768x75", + "1024x768x70", + "1024x768x60", + "1024x768x87i", + "832x624x74", /* rounding error, 74.55 Hz aka "832x624x75" */ + "800x600x75", + "800x600x72", + "800x600x60", + "800x600x56", + "640x480x75", + "640x480x72", + "640x480x67", + "640x480x60", + "720x400x87", /* rounding error, 87.85 Hz aka "720x400x88" */ + "720x400x70", +}; + +#ifdef EDIDVERBOSE +struct edid_vendor { + const char *vendor; + const char *name; +}; + +struct edid_product { + const char *vendor; + uint16_t product; + const char *name; +}; + +#include +#endif /* EDIDVERBOSE */ + +static const char * +edid_findvendor(const char *vendor) +{ +#ifdef EDIDVERBOSE + int n; + + for (n = 0; n < edid_nvendors; n++) + if (memcmp(edid_vendors[n].vendor, vendor, 3) == 0) + return edid_vendors[n].name; +#endif + return NULL; +} + +static const char * +edid_findproduct(const char *vendor, uint16_t product) +{ +#ifdef EDIDVERBOSE + int n; + + for (n = 0; n < edid_nproducts; n++) + if (edid_products[n].product == product && + memcmp(edid_products[n].vendor, vendor, 3) == 0) + return edid_products[n].name; +#endif /* EDIDVERBOSE */ + return NULL; + +} + +static void +edid_strchomp(char *ptr) +{ + for (;;) { + switch (*ptr) { + case '\0': + return; + case '\r': + case '\n': + *ptr = '\0'; + return; + } + ptr++; + } +} + +int +edid_is_valid(uint8_t *d) +{ + int sum = 0, i; + uint8_t sig[8] = EDID_SIGNATURE; + + if (memcmp(d, sig, 8) != 0) + return EINVAL; + + for (i = 0; i < 128; i++) + sum += d[i]; + if ((sum & 0xff) != 0) + return EINVAL; + + return 0; +} + +void +edid_print(struct edid_info *edid) +{ + int i; + + if (edid == NULL) + return; + printf("Vendor: [%s] %s\n", edid->edid_vendor, edid->edid_vendorname); + printf("Product: [%04X] %s\n", edid->edid_product, + edid->edid_productname); + printf("Serial number: %s\n", edid->edid_serial); + printf("Manufactured %d Week %d\n", + edid->edid_year, edid->edid_week); + printf("EDID Version %d.%d\n", edid->edid_version, + edid->edid_revision); + printf("EDID Comment: %s\n", edid->edid_comment); + + printf("Video Input: %x\n", edid->edid_video_input); + if (edid->edid_video_input & EDID_VIDEO_INPUT_DIGITAL) { + printf("\tDigital"); + if (edid->edid_video_input & EDID_VIDEO_INPUT_DFP1_COMPAT) + printf(" (DFP 1.x compatible)"); + printf("\n"); + } else { + printf("\tAnalog\n"); + switch (EDID_VIDEO_INPUT_LEVEL(edid->edid_video_input)) { + case 0: + printf("\t-0.7, 0.3V\n"); + break; + case 1: + printf("\t-0.714, 0.286V\n"); + break; + case 2: + printf("\t-1.0, 0.4V\n"); + break; + case 3: + printf("\t-0.7, 0.0V\n"); + break; + } + if (edid->edid_video_input & EDID_VIDEO_INPUT_BLANK_TO_BLACK) + printf("\tBlank-to-black setup\n"); + if (edid->edid_video_input & EDID_VIDEO_INPUT_SEPARATE_SYNCS) + printf("\tSeperate syncs\n"); + if (edid->edid_video_input & EDID_VIDEO_INPUT_COMPOSITE_SYNC) + printf("\tComposite sync\n"); + if (edid->edid_video_input & EDID_VIDEO_INPUT_SYNC_ON_GRN) + printf("\tSync on green\n"); + if (edid->edid_video_input & EDID_VIDEO_INPUT_SERRATION) + printf("\tSerration vsync\n"); + } + + printf("Gamma: %d.%02d\n", + edid->edid_gamma / 100, edid->edid_gamma % 100); + + printf("Max Size: %d cm x %d cm\n", + edid->edid_max_hsize, edid->edid_max_vsize); + + printf("Features: %x\n", edid->edid_features); + if (edid->edid_features & EDID_FEATURES_STANDBY) + printf("\tDPMS standby\n"); + if (edid->edid_features & EDID_FEATURES_SUSPEND) + printf("\tDPMS suspend\n"); + if (edid->edid_features & EDID_FEATURES_ACTIVE_OFF) + printf("\tDPMS active-off\n"); + switch (EDID_FEATURES_DISP_TYPE(edid->edid_features)) { + case EDID_FEATURES_DISP_TYPE_MONO: + printf("\tMonochrome\n"); + break; + case EDID_FEATURES_DISP_TYPE_RGB: + printf("\tRGB\n"); + break; + case EDID_FEATURES_DISP_TYPE_NON_RGB: + printf("\tMulticolor\n"); + break; + case EDID_FEATURES_DISP_TYPE_UNDEFINED: + printf("\tUndefined monitor type\n"); + break; + } + if (edid->edid_features & EDID_FEATURES_STD_COLOR) + printf("\tStandard color space\n"); + if (edid->edid_features & EDID_FEATURES_PREFERRED_TIMING) + printf("\tPreferred timing\n"); + if (edid->edid_features & EDID_FEATURES_DEFAULT_GTF) + printf("\tDefault GTF supported\n"); + + printf("Chroma Info:\n"); + printf("\tRed X: 0.%03d\n", edid->edid_chroma.ec_redx); + printf("\tRed Y: 0.%03d\n", edid->edid_chroma.ec_redy); + printf("\tGrn X: 0.%03d\n", edid->edid_chroma.ec_greenx); + printf("\tGrn Y: 0.%03d\n", edid->edid_chroma.ec_greeny); + printf("\tBlu X: 0.%03d\n", edid->edid_chroma.ec_bluex); + printf("\tBlu Y: 0.%03d\n", edid->edid_chroma.ec_bluey); + printf("\tWht X: 0.%03d\n", edid->edid_chroma.ec_whitex); + printf("\tWht Y: 0.%03d\n", edid->edid_chroma.ec_whitey); + + if (edid->edid_have_range) { + printf("Range:\n"); + printf("\tHorizontal: %d - %d kHz\n", + edid->edid_range.er_min_hfreq, + edid->edid_range.er_max_hfreq); + printf("\tVertical: %d - %d Hz\n", + edid->edid_range.er_min_vfreq, + edid->edid_range.er_max_vfreq); + printf("\tMax Dot Clock: %d MHz\n", + edid->edid_range.er_max_clock); + if (edid->edid_range.er_have_gtf2) { + printf("\tGTF2 hfreq: %d\n", + edid->edid_range.er_gtf2_hfreq); + printf("\tGTF2 C: %d\n", edid->edid_range.er_gtf2_c); + printf("\tGTF2 M: %d\n", edid->edid_range.er_gtf2_m); + printf("\tGTF2 J: %d\n", edid->edid_range.er_gtf2_j); + printf("\tGTF2 K: %d\n", edid->edid_range.er_gtf2_k); + } + } + printf("Video modes:\n"); + for (i = 0; i < edid->edid_nmodes; i++) { + printf("\t%dx%d @ %dHz", + edid->edid_modes[i].hdisplay, + edid->edid_modes[i].vdisplay, + DIVIDE(DIVIDE(edid->edid_modes[i].dot_clock * 1000, + edid->edid_modes[i].htotal), edid->edid_modes[i].vtotal)); + printf(" (%d %d %d %d %d %d %d", + edid->edid_modes[i].dot_clock, + edid->edid_modes[i].hsync_start, + edid->edid_modes[i].hsync_end, + edid->edid_modes[i].htotal, + edid->edid_modes[i].vsync_start, + edid->edid_modes[i].vsync_end, + edid->edid_modes[i].vtotal); + printf(" %s%sH %s%sV)\n", + edid->edid_modes[i].flags & VID_PHSYNC ? "+" : "", + edid->edid_modes[i].flags & VID_NHSYNC ? "-" : "", + edid->edid_modes[i].flags & VID_PVSYNC ? "+" : "", + edid->edid_modes[i].flags & VID_NVSYNC ? "-" : ""); + } + if (edid->edid_preferred_mode) + printf("Preferred mode: %dx%d @ %dHz\n", + edid->edid_preferred_mode->hdisplay, + edid->edid_preferred_mode->vdisplay, + DIVIDE(DIVIDE(edid->edid_preferred_mode->dot_clock * 1000, + edid->edid_preferred_mode->htotal), + edid->edid_preferred_mode->vtotal)); +} + +static const struct videomode * +edid_mode_lookup_list(const char *name) +{ + int i; + + for (i = 0; i < videomode_count; i++) + if (strcmp(name, videomode_list[i].name) == 0) + return &videomode_list[i]; + return NULL; +} + +static struct videomode * +edid_search_mode(struct edid_info *edid, const struct videomode *mode) +{ + int refresh, i; + + refresh = DIVIDE(DIVIDE(mode->dot_clock * 1000, + mode->htotal), mode->vtotal); + for (i = 0; i < edid->edid_nmodes; i++) { + if (mode->hdisplay == edid->edid_modes[i].hdisplay && + mode->vdisplay == edid->edid_modes[i].vdisplay && + refresh == DIVIDE(DIVIDE( + edid->edid_modes[i].dot_clock * 1000, + edid->edid_modes[i].htotal), edid->edid_modes[i].vtotal)) { + return &edid->edid_modes[i]; + } + } + return NULL; +} + +static int +edid_std_timing(uint8_t *data, struct videomode *vmp) +{ + unsigned x, y, f; + const struct videomode *lookup; + char name[80]; + + if ((data[0] == 1 && data[1] == 1) || + (data[0] == 0 && data[1] == 0) || + (data[0] == 0x20 && data[1] == 0x20)) + return 0; + + x = EDID_STD_TIMING_HRES(data); + switch (EDID_STD_TIMING_RATIO(data)) { + case EDID_STD_TIMING_RATIO_16_10: + y = x * 10 / 16; + break; + case EDID_STD_TIMING_RATIO_4_3: + y = x * 3 / 4; + break; + case EDID_STD_TIMING_RATIO_5_4: + y = x * 4 / 5; + break; + case EDID_STD_TIMING_RATIO_16_9: + default: + y = x * 9 / 16; + break; + } + f = EDID_STD_TIMING_VFREQ(data); + + /* first try to lookup the mode as a DMT timing */ + snprintf(name, sizeof(name), "%dx%dx%d", x, y, f); + if ((lookup = edid_mode_lookup_list(name)) != NULL) { + *vmp = *lookup; + } else { + /* failing that, calculate it using gtf */ + /* + * Hmm. I'm not using alternate GTF timings, which + * could, in theory, be present. + */ + vesagtf_mode(x, y, f, vmp); + } + return 1; +} + +static int +edid_det_timing(uint8_t *data, struct videomode *vmp) +{ + unsigned hactive, hblank, hsyncwid, hsyncoff; + unsigned vactive, vblank, vsyncwid, vsyncoff; + uint8_t flags; + + flags = EDID_DET_TIMING_FLAGS(data); + + /* we don't support stereo modes (for now) */ + if (flags & (EDID_DET_TIMING_FLAG_STEREO | + EDID_DET_TIMING_FLAG_STEREO_MODE)) + return 0; + + vmp->dot_clock = EDID_DET_TIMING_DOT_CLOCK(data) / 1000; + + hactive = EDID_DET_TIMING_HACTIVE(data); + hblank = EDID_DET_TIMING_HBLANK(data); + hsyncwid = EDID_DET_TIMING_HSYNC_WIDTH(data); + hsyncoff = EDID_DET_TIMING_HSYNC_OFFSET(data); + + vactive = EDID_DET_TIMING_VACTIVE(data); + vblank = EDID_DET_TIMING_VBLANK(data); + vsyncwid = EDID_DET_TIMING_VSYNC_WIDTH(data); + vsyncoff = EDID_DET_TIMING_VSYNC_OFFSET(data); + + /* Borders are contained within the blank areas. */ + + vmp->hdisplay = hactive; + vmp->htotal = hactive + hblank; + vmp->hsync_start = hactive + hsyncoff; + vmp->hsync_end = vmp->hsync_start + hsyncwid; + + vmp->vdisplay = vactive; + vmp->vtotal = vactive + vblank; + vmp->vsync_start = vactive + vsyncoff; + vmp->vsync_end = vmp->vsync_start + vsyncwid; + + vmp->flags = 0; + + if (flags & EDID_DET_TIMING_FLAG_INTERLACE) + vmp->flags |= VID_INTERLACE; + if (flags & EDID_DET_TIMING_FLAG_HSYNC_POSITIVE) + vmp->flags |= VID_PHSYNC; + else + vmp->flags |= VID_NHSYNC; + + if (flags & EDID_DET_TIMING_FLAG_VSYNC_POSITIVE) + vmp->flags |= VID_PVSYNC; + else + vmp->flags |= VID_NVSYNC; + + return 1; +} + +static void +edid_block(struct edid_info *edid, uint8_t *data) +{ + int i; + struct videomode mode, *exist_mode; + + if (EDID_BLOCK_IS_DET_TIMING(data)) { + if (!edid_det_timing(data, &mode)) + return; + /* Does this mode already exist? */ + exist_mode = edid_search_mode(edid, &mode); + if (exist_mode != NULL) { + *exist_mode = mode; + if (edid->edid_preferred_mode == NULL) + edid->edid_preferred_mode = exist_mode; + } else { + edid->edid_modes[edid->edid_nmodes] = mode; + if (edid->edid_preferred_mode == NULL) + edid->edid_preferred_mode = + &edid->edid_modes[edid->edid_nmodes]; + edid->edid_nmodes++; + } + return; + } + + switch (EDID_BLOCK_TYPE(data)) { + case EDID_DESC_BLOCK_TYPE_SERIAL: + memcpy(edid->edid_serial, data + EDID_DESC_ASCII_DATA_OFFSET, + EDID_DESC_ASCII_DATA_LEN); + edid->edid_serial[sizeof(edid->edid_serial) - 1] = 0; + break; + + case EDID_DESC_BLOCK_TYPE_ASCII: + memcpy(edid->edid_comment, data + EDID_DESC_ASCII_DATA_OFFSET, + EDID_DESC_ASCII_DATA_LEN); + edid->edid_comment[sizeof(edid->edid_comment) - 1] = 0; + break; + + case EDID_DESC_BLOCK_TYPE_RANGE: + edid->edid_have_range = 1; + edid->edid_range.er_min_vfreq = EDID_DESC_RANGE_MIN_VFREQ(data); + edid->edid_range.er_max_vfreq = EDID_DESC_RANGE_MAX_VFREQ(data); + edid->edid_range.er_min_hfreq = EDID_DESC_RANGE_MIN_HFREQ(data); + edid->edid_range.er_max_hfreq = EDID_DESC_RANGE_MAX_HFREQ(data); + edid->edid_range.er_max_clock = EDID_DESC_RANGE_MAX_CLOCK(data); + if (!EDID_DESC_RANGE_HAVE_GTF2(data)) + break; + edid->edid_range.er_have_gtf2 = 1; + edid->edid_range.er_gtf2_hfreq = + EDID_DESC_RANGE_GTF2_HFREQ(data); + edid->edid_range.er_gtf2_c = EDID_DESC_RANGE_GTF2_C(data); + edid->edid_range.er_gtf2_m = EDID_DESC_RANGE_GTF2_M(data); + edid->edid_range.er_gtf2_j = EDID_DESC_RANGE_GTF2_J(data); + edid->edid_range.er_gtf2_k = EDID_DESC_RANGE_GTF2_K(data); + break; + + case EDID_DESC_BLOCK_TYPE_NAME: + /* copy the product name into place */ + memcpy(edid->edid_productname, + data + EDID_DESC_ASCII_DATA_OFFSET, + EDID_DESC_ASCII_DATA_LEN); + break; + + case EDID_DESC_BLOCK_TYPE_STD_TIMING: + data += EDID_DESC_STD_TIMING_START; + for (i = 0; i < EDID_DESC_STD_TIMING_COUNT; i++) { + if (edid_std_timing(data, &mode)) { + /* Does this mode already exist? */ + exist_mode = edid_search_mode(edid, &mode); + if (exist_mode == NULL) { + edid->edid_modes[edid->edid_nmodes] = + mode; + edid->edid_nmodes++; + } + } + data += 2; + } + break; + + case EDID_DESC_BLOCK_TYPE_COLOR_POINT: + /* XXX: not implemented yet */ + break; + } +} + +/* + * Gets EDID version in BCD, e.g. EDID v1.3 returned as 0x0103 + */ +int +edid_parse(uint8_t *data, struct edid_info *edid) +{ + uint16_t manfid, estmodes; + const struct videomode *vmp; + int i; + const char *name; + int max_dotclock = 0; + int mhz; + + if (edid_is_valid(data) != 0) + return -1; + + /* get product identification */ + manfid = EDID_VENDOR_ID(data); + edid->edid_vendor[0] = EDID_MANFID_0(manfid); + edid->edid_vendor[1] = EDID_MANFID_1(manfid); + edid->edid_vendor[2] = EDID_MANFID_2(manfid); + edid->edid_vendor[3] = 0; /* null terminate for convenience */ + + edid->edid_product = data[EDID_OFFSET_PRODUCT_ID] + + (data[EDID_OFFSET_PRODUCT_ID + 1] << 8); + + name = edid_findvendor(edid->edid_vendor); + if (name != NULL) + strlcpy(edid->edid_vendorname, name, + sizeof(edid->edid_vendorname)); + else + edid->edid_vendorname[0] = '\0'; + + name = edid_findproduct(edid->edid_vendor, edid->edid_product); + if (name != NULL) + strlcpy(edid->edid_productname, name, + sizeof(edid->edid_productname)); + else + edid->edid_productname[0] = '\0'; + + snprintf(edid->edid_serial, sizeof(edid->edid_serial), "%08x", + EDID_SERIAL_NUMBER(data)); + + edid->edid_week = EDID_WEEK(data); + edid->edid_year = EDID_YEAR(data); + + /* get edid revision */ + edid->edid_version = EDID_VERSION(data); + edid->edid_revision = EDID_REVISION(data); + + edid->edid_video_input = EDID_VIDEO_INPUT(data); + edid->edid_max_hsize = EDID_MAX_HSIZE(data); + edid->edid_max_vsize = EDID_MAX_VSIZE(data); + + edid->edid_gamma = EDID_GAMMA(data); + edid->edid_features = EDID_FEATURES(data); + + edid->edid_chroma.ec_redx = EDID_CHROMA_REDX(data); + edid->edid_chroma.ec_redy = EDID_CHROMA_REDX(data); + edid->edid_chroma.ec_greenx = EDID_CHROMA_GREENX(data); + edid->edid_chroma.ec_greeny = EDID_CHROMA_GREENY(data); + edid->edid_chroma.ec_bluex = EDID_CHROMA_BLUEX(data); + edid->edid_chroma.ec_bluey = EDID_CHROMA_BLUEY(data); + edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITEX(data); + edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITEY(data); + + /* lookup established modes */ + edid->edid_nmodes = 0; + edid->edid_preferred_mode = NULL; + estmodes = EDID_EST_TIMING(data); + /* Iterate in esztablished timing order */ + for (i = 15; i >= 0; i--) { + if (estmodes & (1 << i)) { + vmp = edid_mode_lookup_list(_edid_modes[i]); + if (vmp != NULL) { + edid->edid_modes[edid->edid_nmodes] = *vmp; + edid->edid_nmodes++; + } +#ifdef DIAGNOSTIC + else + printf("no data for est. mode %s\n", + _edid_modes[i]); +#endif + } + } + + /* do standard timing section */ + for (i = 0; i < EDID_STD_TIMING_COUNT; i++) { + struct videomode mode, *exist_mode; + if (edid_std_timing(data + EDID_OFFSET_STD_TIMING + i * 2, + &mode)) { + /* Does this mode already exist? */ + exist_mode = edid_search_mode(edid, &mode); + if (exist_mode == NULL) { + edid->edid_modes[edid->edid_nmodes] = mode; + edid->edid_nmodes++; + } + } + } + + /* do detailed timings and descriptors */ + for (i = 0; i < EDID_BLOCK_COUNT; i++) { + edid_block(edid, data + EDID_OFFSET_DESC_BLOCK + + i * EDID_BLOCK_SIZE); + } + + edid_strchomp(edid->edid_vendorname); + edid_strchomp(edid->edid_productname); + edid_strchomp(edid->edid_serial); + edid_strchomp(edid->edid_comment); + + /* + * XXX + * some monitors lie about their maximum supported dot clock + * by claiming to support modes which need a higher dot clock + * than the stated maximum. + * For sanity's sake we bump it to the highest dot clock we find + * in the list of supported modes + */ + for (i = 0; i < edid->edid_nmodes; i++) + if (edid->edid_modes[i].dot_clock > max_dotclock) + max_dotclock = edid->edid_modes[i].dot_clock; + + aprint_debug("max_dotclock according to supported modes: %d\n", + max_dotclock); + + mhz = (max_dotclock + 999) / 1000; + + if (edid->edid_have_range) { + if (mhz > edid->edid_range.er_max_clock) + edid->edid_range.er_max_clock = mhz; + } else + edid->edid_range.er_max_clock = mhz; + + return 0; +} + diff --git a/sys/dev/videomode/ediddevs b/sys/dev/videomode/ediddevs new file mode 100644 index 000000000..389dc1d09 --- /dev/null +++ b/sys/dev/videomode/ediddevs @@ -0,0 +1,105 @@ +$NetBSD: ediddevs,v 1.3 2009/01/21 14:40:02 jnemeth Exp $ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Use "make -f Makefile.ediddevs" to regenerate ediddevs.h and ediddevs_data.h + */ + +/* + * List of known EDID monitor vendors + * + * These are standard PNP ids, managed (apparently) by Microsoft. + * It is likely that this list is grossly incomplete. + */ +vendor AAC AcerView +vendor AOC AOC +vendor APP Apple Computer +vendor AST AST Research +vendor CPL Compal +vendor CPQ Compaq +vendor CTX CTX +vendor DEC DEC +vendor DEL Dell +vendor DPC Delta +vendor DWE Daewoo +vendor EIZ EIZO +vendor ELS ELSA +vendor EPI Envision +vendor FCM Funai +vendor FUJ Fujitsu +vendor GSM LG Electronics +vendor GWY Gateway 2000 +vendor HEI Hyundai +vendor HIT Hitachi +vendor HSL Hansol +vendor HTC Hitachi/Nissei +vendor HWP HP +vendor IBM IBM +vendor ICL Fujitsu ICL +vendor IVM Iiyama +vendor KDS Korea Data Systems +vendor MEI Panasonic +vendor MEL Mitsubishi Electronics +vendor NAN Nanao +vendor NEC NEC +vendor NOK Nokia Data +vendor PHL Philips +vendor REL Relisys +vendor SAM Samsung +vendor SGI SGI +vendor SNY Sony +vendor SRC Shamrock +vendor SUN Sun Microsystems +vendor TAT Tatung +vendor TOS Toshiba +vendor TSB Toshiba +vendor VSC ViewSonic +vendor ZCM Zenith + +/* + * List of known products, grouped and sorted by vendor. + * + * EDID version 1.3 requires that monitors expose the monitor name with + * the ASCII descriptor type 0xFC, so for monitors using that block, this + * information is redundant, and there is not point in listing them here, + * unless it is desired to have a symbolic macro to detect the monitor in + * special handling code or somesuch. + */ + +/* Dell - this exists for now as a sample. I don't have one of these. */ +product DEL ULTRASCAN14XE_REVA 0x139A Ultrascan 14XE +product DEL ULTRASCAN14XE_REVB 0x139B Ultrascan 14XE + +/* ViewSonic */ +product VSC 17GS 0x0c00 17GS +product VSC 17PS 0x0c0f 17PS diff --git a/sys/dev/videomode/ediddevs.h b/sys/dev/videomode/ediddevs.h new file mode 100644 index 000000000..7aded2d39 --- /dev/null +++ b/sys/dev/videomode/ediddevs.h @@ -0,0 +1,91 @@ +/* $NetBSD: ediddevs.h,v 1.2 2007/03/07 18:47:55 macallan Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * NetBSD: ediddevs,v 1.1 2006/05/11 01:49:53 gdamore Exp + */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define EDID_VENDOR_AAC "AcerView" +#define EDID_VENDOR_AOC "AOC" +#define EDID_VENDOR_APP "Apple Computer" +#define EDID_VENDOR_AST "AST Research" +#define EDID_VENDOR_CPL "Compal" +#define EDID_VENDOR_CPQ "Compaq" +#define EDID_VENDOR_CTX "CTX" +#define EDID_VENDOR_DEC "DEC" +#define EDID_VENDOR_DEL "Dell" +#define EDID_VENDOR_DPC "Delta" +#define EDID_VENDOR_DWE "Daewoo" +#define EDID_VENDOR_EIZ "EIZO" +#define EDID_VENDOR_ELS "ELSA" +#define EDID_VENDOR_EPI "Envision" +#define EDID_VENDOR_FCM "Funai" +#define EDID_VENDOR_FUJ "Fujitsu" +#define EDID_VENDOR_GSM "LG Electronics" +#define EDID_VENDOR_GWY "Gateway 2000" +#define EDID_VENDOR_HEI "Hyundai" +#define EDID_VENDOR_HIT "Hitachi" +#define EDID_VENDOR_HSL "Hansol" +#define EDID_VENDOR_HTC "Hitachi/Nissei" +#define EDID_VENDOR_HWP "HP" +#define EDID_VENDOR_IBM "IBM" +#define EDID_VENDOR_ICL "Fujitsu ICL" +#define EDID_VENDOR_IVM "Iiyama" +#define EDID_VENDOR_KDS "Korea Data Systems" +#define EDID_VENDOR_MEI "Panasonic" +#define EDID_VENDOR_MEL "Mitsubishi Electronics" +#define EDID_VENDOR_NAN "Nanao" +#define EDID_VENDOR_NEC "NEC" +#define EDID_VENDOR_NOK "Nokia Data" +#define EDID_VENDOR_PHL "Philips" +#define EDID_VENDOR_REL "Relisys" +#define EDID_VENDOR_SAM "Samsung" +#define EDID_VENDOR_SGI "SGI" +#define EDID_VENDOR_SNY "Sony" +#define EDID_VENDOR_SRC "Shamrock" +#define EDID_VENDOR_SUN "Sun Microsystems" +#define EDID_VENDOR_TAT "Tatung" +#define EDID_VENDOR_TOS "Toshiba" +#define EDID_VENDOR_TSB "Toshiba" +#define EDID_VENDOR_VSC "ViewSonic" +#define EDID_VENDOR_ZCM "Zenith" + +/* Dell - this exists for now as a sample. I don't have one of these. */ +#define EDID_PRODUCT_DEL_ULTRASCAN14XE_REVA 0x139A /* Ultrascan 14XE */ +#define EDID_PRODUCT_DEL_ULTRASCAN14XE_REVB 0x139B /* Ultrascan 14XE */ + +/* ViewSonic */ +#define EDID_PRODUCT_VSC_17GS 0x0c00 /* 17GS */ +#define EDID_PRODUCT_VSC_17PS 0x0c0f /* 17PS */ diff --git a/sys/dev/videomode/ediddevs_data.h b/sys/dev/videomode/ediddevs_data.h new file mode 100644 index 000000000..25bcf2600 --- /dev/null +++ b/sys/dev/videomode/ediddevs_data.h @@ -0,0 +1,107 @@ +/* $NetBSD: ediddevs_data.h,v 1.2 2007/03/07 18:47:13 macallan Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * NetBSD: ediddevs,v 1.1 2006/05/11 01:49:53 gdamore Exp + */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +const struct edid_vendor edid_vendors[] = { + { "AAC", EDID_VENDOR_AAC }, + { "AOC", EDID_VENDOR_AOC }, + { "APP", EDID_VENDOR_APP }, + { "AST", EDID_VENDOR_AST }, + { "CPL", EDID_VENDOR_CPL }, + { "CPQ", EDID_VENDOR_CPQ }, + { "CTX", EDID_VENDOR_CTX }, + { "DEC", EDID_VENDOR_DEC }, + { "DEL", EDID_VENDOR_DEL }, + { "DPC", EDID_VENDOR_DPC }, + { "DWE", EDID_VENDOR_DWE }, + { "EIZ", EDID_VENDOR_EIZ }, + { "ELS", EDID_VENDOR_ELS }, + { "EPI", EDID_VENDOR_EPI }, + { "FCM", EDID_VENDOR_FCM }, + { "FUJ", EDID_VENDOR_FUJ }, + { "GSM", EDID_VENDOR_GSM }, + { "GWY", EDID_VENDOR_GWY }, + { "HEI", EDID_VENDOR_HEI }, + { "HIT", EDID_VENDOR_HIT }, + { "HSL", EDID_VENDOR_HSL }, + { "HTC", EDID_VENDOR_HTC }, + { "HWP", EDID_VENDOR_HWP }, + { "IBM", EDID_VENDOR_IBM }, + { "ICL", EDID_VENDOR_ICL }, + { "IVM", EDID_VENDOR_IVM }, + { "KDS", EDID_VENDOR_KDS }, + { "MEI", EDID_VENDOR_MEI }, + { "MEL", EDID_VENDOR_MEL }, + { "NAN", EDID_VENDOR_NAN }, + { "NEC", EDID_VENDOR_NEC }, + { "NOK", EDID_VENDOR_NOK }, + { "PHL", EDID_VENDOR_PHL }, + { "REL", EDID_VENDOR_REL }, + { "SAM", EDID_VENDOR_SAM }, + { "SGI", EDID_VENDOR_SGI }, + { "SNY", EDID_VENDOR_SNY }, + { "SRC", EDID_VENDOR_SRC }, + { "SUN", EDID_VENDOR_SUN }, + { "TAT", EDID_VENDOR_TAT }, + { "TOS", EDID_VENDOR_TOS }, + { "TSB", EDID_VENDOR_TSB }, + { "VSC", EDID_VENDOR_VSC }, + { "ZCM", EDID_VENDOR_ZCM }, +}; +const int edid_nvendors = 44; + +const struct edid_product edid_products[] = { + { + "DEL", EDID_PRODUCT_DEL_ULTRASCAN14XE_REVA, + "Ultrascan 14XE", + }, + { + "DEL", EDID_PRODUCT_DEL_ULTRASCAN14XE_REVB, + "Ultrascan 14XE", + }, + { + "VSC", EDID_PRODUCT_VSC_17GS, + "17GS", + }, + { + "VSC", EDID_PRODUCT_VSC_17PS, + "17PS", + }, +}; +const int edid_nproducts = 4; diff --git a/sys/dev/videomode/edidreg.h b/sys/dev/videomode/edidreg.h new file mode 100644 index 000000000..5d448f3c5 --- /dev/null +++ b/sys/dev/videomode/edidreg.h @@ -0,0 +1,253 @@ +/* $NetBSD: edidreg.h,v 1.3 2011/03/30 18:49:56 jdc Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_VIDEOMODE_EDIDREG_H +#define _DEV_VIDEOMODE_EDIDREG_H + +#define EDID_OFFSET_SIGNATURE 0x00 +#define EDID_OFFSET_MANUFACTURER_ID 0x08 +#define EDID_OFFSET_PRODUCT_ID 0x0a +#define EDID_OFFSET_SERIAL_NUMBER 0x0c +#define EDID_OFFSET_MANUFACTURE_WEEK 0x10 +#define EDID_OFFSET_MANUFACTURE_YEAR 0x11 +#define EDID_OFFSET_VERSION 0x12 +#define EDID_OFFSET_REVISION 0x13 +#define EDID_OFFSET_VIDEO_INPUT 0x14 +#define EDID_OFFSET_MAX_HSIZE 0x15 /* in cm */ +#define EDID_OFFSET_MAX_VSIZE 0x16 +#define EDID_OFFSET_GAMMA 0x17 +#define EDID_OFFSET_FEATURE 0x18 +#define EDID_OFFSET_CHROMA 0x19 +#define EDID_OFFSET_EST_TIMING_1 0x23 +#define EDID_OFFSET_EST_TIMING_2 0x24 +#define EDID_OFFSET_MFG_TIMING 0x25 +#define EDID_OFFSET_STD_TIMING 0x26 +#define EDID_OFFSET_DESC_BLOCK 0x36 + +#define EDID_SIGNATURE { 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0 } + +/* assume x is 16-bit value */ +#define EDID_VENDOR_ID(ptr) ((((ptr)[8]) << 8) + ptr[9]) +#define EDID_MANFID_0(x) ((((x) >> 10) & 0x1f) + '@') +#define EDID_MANFID_1(x) ((((x) >> 5) & 0x1f) + '@') +#define EDID_MANFID_2(x) ((((x) >> 0) & 0x1f) + '@') + +/* relative to edid block */ +#define EDID_PRODUCT_ID(ptr) (((ptr)[10]) | (((ptr)[11]) << 8)) +#define EDID_SERIAL_NUMBER(ptr) (((ptr)[12] << 24) + \ + ((ptr)[13] << 16) + \ + ((ptr)[14] << 8) + \ + (ptr)[15]) + +/* relative to edid block */ +#define EDID_WEEK(ptr) ((ptr)[16]) +#define EDID_YEAR(ptr) (((ptr)[17]) + 1990) + +#define EDID_VERSION(ptr) ((ptr)[18]) +#define EDID_REVISION(ptr) ((ptr)[19]) + +#define EDID_VIDEO_INPUT(ptr) ((ptr)[20]) +#define EDID_VIDEO_INPUT_DIGITAL 0x80 +/* if INPUT_BIT_DIGITAL set */ +#define EDID_VIDEO_INPUT_DFP1_COMPAT 0x01 +/* if INPUT_BIT_DIGITAL not set */ +#define EDID_VIDEO_INPUT_BLANK_TO_BLACK 0x10 +#define EDID_VIDEO_INPUT_SEPARATE_SYNCS 0x08 +#define EDID_VIDEO_INPUT_COMPOSITE_SYNC 0x04 +#define EDID_VIDEO_INPUT_SYNC_ON_GRN 0x02 +#define EDID_VIDEO_INPUT_SERRATION 0x01 +#define EDID_VIDEO_INPUT_LEVEL(x) (((x) & 0x60) >> 5) +/* meanings of level bits are as follows, I don't know names */ +/* 0 = 0.7,0.3, 1 = 0.714,0.286, 2 = 1.0,0.4, 3 = 0.7,0.0 */ + +/* relative to edid block */ +#define EDID_MAX_HSIZE(ptr) ((ptr)[21]) /* cm */ +#define EDID_MAX_VSIZE(ptr) ((ptr)[22]) /* cm */ +/* gamma is scaled by 100 (avoid fp), e.g. 213 == 2.13 */ +#define _GAMMA(x) ((x) == 0xff ? 100 : ((x) + 100)) +#define EDID_GAMMA(ptr) _GAMMA(ptr[23]) + +#define EDID_FEATURES(ptr) ((ptr)[24]) +#define EDID_FEATURES_STANDBY 0x80 +#define EDID_FEATURES_SUSPEND 0x40 +#define EDID_FEATURES_ACTIVE_OFF 0x20 +#define EDID_FEATURES_DISP_TYPE(x) (((x) & 0x18) >> 3) +#define EDID_FEATURES_DISP_TYPE_MONO 0 +#define EDID_FEATURES_DISP_TYPE_RGB 1 +#define EDID_FEATURES_DISP_TYPE_NON_RGB 2 +#define EDID_FEATURES_DISP_TYPE_UNDEFINED 3 +#define EDID_FEATURES_STD_COLOR 0x04 +#define EDID_FEATURES_PREFERRED_TIMING 0x02 +#define EDID_FEATURES_DEFAULT_GTF 0x01 + +/* chroma values 0.0 - 0.999 scaled as 0-999 */ +#define _CHLO(byt, shft) (((byt) >> (shft)) & 0x3) +#define _CHHI(byt) ((byt) << 2) +#define _CHHILO(ptr, l, s, h) (_CHLO((ptr)[l], s) | _CHHI((ptr)[h])) +#define _CHROMA(ptr, l, s, h) ((_CHHILO(ptr, l, s, h) * 1000) / 1024) + +#define EDID_CHROMA_REDX(ptr) (_CHROMA(ptr, 25, 6, 27)) +#define EDID_CHROMA_REDY(ptr) (_CHROMA(ptr, 25, 4, 28)) +#define EDID_CHROMA_GREENX(ptr) (_CHROMA(ptr, 25, 2, 29)) +#define EDID_CHROMA_GREENY(ptr) (_CHROMA(ptr, 25, 0, 30)) +#define EDID_CHROMA_BLUEX(ptr) (_CHROMA(ptr, 26, 6, 31)) +#define EDID_CHROMA_BLUEY(ptr) (_CHROMA(ptr, 26, 4, 32)) +#define EDID_CHROMA_WHITEX(ptr) (_CHROMA(ptr, 26, 2, 33)) +#define EDID_CHROMA_WHITEY(ptr) (_CHROMA(ptr, 26, 0, 34)) + +/* relative to edid block */ +#define EDID_EST_TIMING(ptr) (((ptr)[35] << 8) | (ptr)[36]) +#define EDID_EST_TIMING_720_400_70 0x8000 /* 720x400 @ 70Hz */ +#define EDID_EST_TIMING_720_400_88 0x4000 /* 720x400 @ 88Hz */ +#define EDID_EST_TIMING_640_480_60 0x2000 /* 640x480 @ 60Hz */ +#define EDID_EST_TIMING_640_480_67 0x1000 /* 640x480 @ 67Hz */ +#define EDID_EST_TIMING_640_480_72 0x0800 /* 640x480 @ 72Hz */ +#define EDID_EST_TIMING_640_480_75 0x0400 /* 640x480 @ 75Hz */ +#define EDID_EST_TIMING_800_600_56 0x0200 /* 800x600 @ 56Hz */ +#define EDID_EST_TIMING_800_600_60 0x0100 /* 800x600 @ 60Hz */ +#define EDID_EST_TIMING_800_600_72 0x0080 /* 800x600 @ 72Hz */ +#define EDID_EST_TIMING_800_600_75 0x0040 /* 800x600 @ 75Hz */ +#define EDID_EST_TIMING_832_624_75 0x0020 /* 832x624 @ 75Hz */ +#define EDID_EST_TIMING_1024_768_87I 0x0010 /* 1024x768i @ 87Hz */ +#define EDID_EST_TIMING_1024_768_60 0x0008 /* 1024x768 @ 60Hz */ +#define EDID_EST_TIMING_1024_768_70 0x0004 /* 1024x768 @ 70Hz */ +#define EDID_EST_TIMING_1024_768_75 0x0002 /* 1024x768 @ 75Hz */ +#define EDID_EST_TIMING_1280_1024_75 0x0001 /* 1280x1024 @ 75Hz */ + +/* + * N.B.: ptr is relative to standard timing block - used for standard timing + * descriptors as well as standard timings section of edid! + */ +#define EDID_STD_TIMING_HRES(ptr) ((((ptr)[0]) * 8) + 248) +#define EDID_STD_TIMING_VFREQ(ptr) ((((ptr)[1]) & 0x3f) + 60) +#define EDID_STD_TIMING_RATIO(ptr) ((ptr)[1] & 0xc0) +#define EDID_STD_TIMING_RATIO_16_10 0x00 +#define EDID_STD_TIMING_RATIO_4_3 0x40 +#define EDID_STD_TIMING_RATIO_5_4 0x80 +#define EDID_STD_TIMING_RATIO_16_9 0xc0 + +#define EDID_STD_TIMING_SIZE 16 +#define EDID_STD_TIMING_COUNT 8 + +/* + * N.B.: ptr is relative to descriptor block start + */ +#define EDID_BLOCK_SIZE 18 +#define EDID_BLOCK_COUNT 4 + +/* detailed timing block.... what a mess */ +#define EDID_BLOCK_IS_DET_TIMING(ptr) ((ptr)[0] | (ptr)[1]) + +#define EDID_DET_TIMING_DOT_CLOCK(ptr) (((ptr)[0] | ((ptr)[1] << 8)) * 10000) +#define _HACT_LO(ptr) ((ptr)[2]) +#define _HBLK_LO(ptr) ((ptr)[3]) +#define _HACT_HI(ptr) (((ptr)[4] & 0xf0) << 4) +#define _HBLK_HI(ptr) (((ptr)[4] & 0x0f) << 8) +#define EDID_DET_TIMING_HACTIVE(ptr) (_HACT_LO(ptr) | _HACT_HI(ptr)) +#define EDID_DET_TIMING_HBLANK(ptr) (_HBLK_LO(ptr) | _HBLK_HI(ptr)) +#define _VACT_LO(ptr) ((ptr)[5]) +#define _VBLK_LO(ptr) ((ptr)[6]) +#define _VACT_HI(ptr) (((ptr)[7] & 0xf0) << 4) +#define _VBLK_HI(ptr) (((ptr)[7] & 0x0f) << 8) +#define EDID_DET_TIMING_VACTIVE(ptr) (_VACT_LO(ptr) | _VACT_HI(ptr)) +#define EDID_DET_TIMING_VBLANK(ptr) (_VBLK_LO(ptr) | _VBLK_HI(ptr)) +#define _HOFF_LO(ptr) ((ptr)[8]) +#define _HWID_LO(ptr) ((ptr)[9]) +#define _VOFF_LO(ptr) ((ptr)[10] >> 4) +#define _VWID_LO(ptr) ((ptr)[10] & 0xf) +#define _HOFF_HI(ptr) (((ptr)[11] & 0xc0) << 2) +#define _HWID_HI(ptr) (((ptr)[11] & 0x30) << 4) +#define _VOFF_HI(ptr) (((ptr)[11] & 0x0c) << 2) +#define _VWID_HI(ptr) (((ptr)[11] & 0x03) << 4) +#define EDID_DET_TIMING_HSYNC_OFFSET(ptr) (_HOFF_LO(ptr) | _HOFF_HI(ptr)) +#define EDID_DET_TIMING_HSYNC_WIDTH(ptr) (_HWID_LO(ptr) | _HWID_HI(ptr)) +#define EDID_DET_TIMING_VSYNC_OFFSET(ptr) (_VOFF_LO(ptr) | _VOFF_HI(ptr)) +#define EDID_DET_TIMING_VSYNC_WIDTH(ptr) (_VWID_LO(ptr) | _VWID_HI(ptr)) +#define _HSZ_LO(ptr) ((ptr)[12]) +#define _VSZ_LO(ptr) ((ptr)[13]) +#define _HSZ_HI(ptr) (((ptr)[14] & 0xf0) << 4) +#define _VSZ_HI(ptr) (((ptr)[14] & 0x0f) << 8) +#define EDID_DET_TIMING_HSIZE(ptr) (_HSZ_LO(ptr) | _HSZ_HI(ptr)) +#define EDID_DET_TIMING_VSIZE(ptr) (_VSZ_LO(ptr) | _VSZ_HI(ptr)) +#define EDID_DET_TIMING_HBORDER(ptr) ((ptr)[15]) +#define EDID_DET_TIMING_VBORDER(ptr) ((ptr)[16]) +#define EDID_DET_TIMING_FLAGS(ptr) ((ptr)[17]) +#define EDID_DET_TIMING_FLAG_INTERLACE 0x80 +#define EDID_DET_TIMING_FLAG_STEREO 0x60 /* stereo or not */ +#define EDID_DET_TIMING_FLAG_SYNC_SEPARATE 0x18 +#define EDID_DET_TIMING_FLAG_VSYNC_POSITIVE 0x04 +#define EDID_DET_TIMING_FLAG_HSYNC_POSITIVE 0x02 +#define EDID_DET_TIMING_FLAG_STEREO_MODE 0x01 /* stereo mode */ + + +/* N.B.: these tests assume that we already checked for detailed timing! */ +#define EDID_BLOCK_TYPE(ptr) ((ptr)[3]) + +#define EDID_DESC_BLOCK_SIZE 18 +#define EDID_DESC_BLOCK_TYPE_SERIAL 0xFF +#define EDID_DESC_BLOCK_TYPE_ASCII 0xFE +#define EDID_DESC_BLOCK_TYPE_RANGE 0xFD +#define EDID_DESC_BLOCK_TYPE_NAME 0xFC +#define EDID_DESC_BLOCK_TYPE_COLOR_POINT 0xFB +#define EDID_DESC_BLOCK_TYPE_STD_TIMING 0xFA + +/* used for descriptors 0xFF, 0xFE, and 0xFC */ +#define EDID_DESC_ASCII_DATA_OFFSET 5 +#define EDID_DESC_ASCII_DATA_LEN 13 + +#define EDID_DESC_RANGE_MIN_VFREQ(ptr) ((ptr)[5]) /* Hz */ +#define EDID_DESC_RANGE_MAX_VFREQ(ptr) ((ptr)[6]) /* Hz */ +#define EDID_DESC_RANGE_MIN_HFREQ(ptr) ((ptr)[7]) /* kHz */ +#define EDID_DESC_RANGE_MAX_HFREQ(ptr) ((ptr)[8]) /* kHz */ +#define EDID_DESC_RANGE_MAX_CLOCK(ptr) (((ptr)[9]) * 10) /* MHz */ +#define EDID_DESC_RANGE_HAVE_GTF2(ptr) (((ptr)[10]) == 0x02) +#define EDID_DESC_RANGE_GTF2_HFREQ(ptr) (((ptr)[12]) * 2) +#define EDID_DESC_RANGE_GTF2_C(ptr) (((ptr)[13]) / 2) +#define EDID_DESC_RANGE_GTF2_M(ptr) ((ptr)[14] + ((ptr)[15] << 8)) +#define EDID_DESC_RANGE_GTF2_K(ptr) ((ptr)[16]) +#define EDID_DESC_RANGE_GTF2_J(ptr) ((ptr)[17] / 2) + +#define EDID_DESC_COLOR_WHITEX(ptr) +#define EDID_DESC_COLOR_WHITE_INDEX_1(ptr) ((ptr)[5]) +#define EDID_DESC_COLOR_WHITEX_1(ptr) _CHROMA(ptr, 6, 2, 7) +#define EDID_DESC_COLOR_WHITEY_1(ptr) _CHROMA(ptr, 6, 0, 8) +#define EDID_DESC_COLOR_GAMMA_1(ptr) _GAMMA(ptr[9]) +#define EDID_DESC_COLOR_WHITE_INDEX_2(ptr) ((ptr)[10]) +#define EDID_DESC_COLOR_WHITEX_2(ptr) _CHROMA(ptr, 11, 2, 12) +#define EDID_DESC_COLOR_WHITEY_2(ptr) _CHROMA(ptr, 11, 0, 13) +#define EDID_DESC_COLOR_GAMMA_2(ptr) _GAMMA(ptr[14]) + +#define EDID_DESC_STD_TIMING_START 5 +#define EDID_DESC_STD_TIMING_COUNT 6 + +#endif /* _DEV_VIDEOMODE_EDIDREG_H */ diff --git a/sys/dev/videomode/edidvar.h b/sys/dev/videomode/edidvar.h new file mode 100644 index 000000000..bfbf01f36 --- /dev/null +++ b/sys/dev/videomode/edidvar.h @@ -0,0 +1,94 @@ +/* $NetBSD: edidvar.h,v 1.2 2006/05/11 19:05:41 gdamore Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_VIDEOMODE_EDIDVAR_H +#define _DEV_VIDEOMODE_EDIDVAR_H + +struct edid_chroma { + uint16_t ec_redx; + uint16_t ec_redy; + uint16_t ec_greenx; + uint16_t ec_greeny; + uint16_t ec_bluex; + uint16_t ec_bluey; + uint16_t ec_whitex; + uint16_t ec_whitey; +}; + +struct edid_range { + uint16_t er_min_vfreq; /* Hz */ + uint16_t er_max_vfreq; /* Hz */ + uint16_t er_min_hfreq; /* kHz */ + uint16_t er_max_hfreq; /* kHz */ + uint16_t er_max_clock; /* MHz */ + int er_have_gtf2; + uint16_t er_gtf2_hfreq; + uint16_t er_gtf2_c; + uint16_t er_gtf2_m; + uint16_t er_gtf2_k; + uint16_t er_gtf2_j; +}; + +struct edid_info { + uint8_t edid_vendor[4]; + char edid_vendorname[16]; + char edid_productname[16]; + char edid_comment[16]; + char edid_serial[16]; + uint16_t edid_product; + uint8_t edid_version; + uint8_t edid_revision; + int edid_year; + int edid_week; + uint8_t edid_video_input; /* see edidregs.h */ + uint8_t edid_max_hsize; /* in cm */ + uint8_t edid_max_vsize; /* in cm */ + uint8_t edid_gamma; + uint8_t edid_features; + + int edid_have_range; + struct edid_range edid_range; + + struct edid_chroma edid_chroma; + + /* parsed modes */ + struct videomode *edid_preferred_mode; + int edid_nmodes; + struct videomode edid_modes[64]; +}; + +int edid_is_valid(uint8_t *); +int edid_parse(uint8_t *, struct edid_info *); +void edid_print(struct edid_info *); + +#endif /* _DEV_VIDEOMODE_EDIDVAR_H */ diff --git a/sys/dev/videomode/files.videomode b/sys/dev/videomode/files.videomode new file mode 100644 index 000000000..788e4b617 --- /dev/null +++ b/sys/dev/videomode/files.videomode @@ -0,0 +1,13 @@ +# $NetBSD: files.videomode,v 1.4 2010/05/04 21:17:10 macallan Exp $ + +define videomode +define edid +define vesagtf + +file dev/videomode/videomode.c videomode | edid + +file dev/videomode/edid.c edid +file dev/videomode/pickmode.c videomode +defflag opt_videomode.h PICKMODE_DEBUG + +file dev/videomode/vesagtf.c vesagtf | edid diff --git a/sys/dev/videomode/modelines b/sys/dev/videomode/modelines new file mode 100644 index 000000000..3498d4bbc --- /dev/null +++ b/sys/dev/videomode/modelines @@ -0,0 +1,180 @@ +// $NetBSD: modelines,v 1.9 2011/03/30 18:45:04 jdc Exp $ +// +// This file was imported from XFree86, and is made of the contents of both +// the vesamodes and extramodes files. As a result these should correspond +// to the same default modes compiled into XFree86. +// +// Default modes distilled from +// "VESA and Industry Standards and Guide for Computer Display Monitor +// Timing", version 1.0, revision 0.8, adopted September 17, 1998. +// +// $XFree86: xc/programs/Xserver/hw/xfree86/etc/vesamodes,v 1.3 1999/11/16 03:28:03 tsi Exp $ +// $XFree86: xc/programs/Xserver/hw/xfree86/etc/extramodes,v 1.5 2002/06/05 19:43:05 dawes Exp $ +// +// +// Use "make -f Makefile.videomode" to regenerate videomode.c +// + +# 640x350 @ 85Hz (VESA) hsync: 37.9kHz +ModeLine "640x350" 31.5 640 672 736 832 350 382 385 445 +hsync -vsync + +# 640x400 @ 85Hz (VESA) hsync: 37.9kHz +ModeLine "640x400" 31.5 640 672 736 832 400 401 404 445 -hsync +vsync + +# 720x400 @ 70Hz (EDID established timing) hsync: 31.47kHz +ModeLine "720x400" 28.32 720 738 846 900 400 412 414 449 -hsync +vsync + +# 720x400 @ 85Hz (VESA) hsync: 37.9kHz +ModeLine "720x400" 35.5 720 756 828 936 400 401 404 446 -hsync +vsync + +# 720x400 @ 88Hz (EDID established timing) hsync: 39.44kHz +ModeLine "720x400" 35.5 720 738 846 900 400 421 423 449 -hsync -vsync + +# 640x480 @ 60Hz (Industry standard) hsync: 31.5kHz +ModeLine "640x480" 25.175 640 656 752 800 480 490 492 525 -hsync -vsync + +# 640x480 @ 72Hz (VESA) hsync: 37.9kHz +ModeLine "640x480" 31.5 640 664 704 832 480 489 492 520 -hsync -vsync + +# 640x480 @ 75Hz (VESA) hsync: 37.5kHz +ModeLine "640x480" 31.5 640 656 720 840 480 481 484 500 -hsync -vsync + +# 640x480 @ 85Hz (VESA) hsync: 43.3kHz +ModeLine "640x480" 36.0 640 696 752 832 480 481 484 509 -hsync -vsync + +# 800x600 @ 56Hz (VESA) hsync: 35.2kHz +ModeLine "800x600" 36.0 800 824 896 1024 600 601 603 625 +hsync +vsync + +# 800x600 @ 60Hz (VESA) hsync: 37.9kHz +ModeLine "800x600" 40.0 800 840 968 1056 600 601 605 628 +hsync +vsync + +# 800x600 @ 72Hz (VESA) hsync: 48.1kHz +ModeLine "800x600" 50.0 800 856 976 1040 600 637 643 666 +hsync +vsync + +# 800x600 @ 75Hz (VESA) hsync: 46.9kHz +ModeLine "800x600" 49.5 800 816 896 1056 600 601 604 625 +hsync +vsync + +# 800x600 @ 85Hz (VESA) hsync: 53.7kHz +ModeLine "800x600" 56.25 800 832 896 1048 600 601 604 631 +hsync +vsync + +# 1024x768i @ 43Hz (industry standard) hsync: 35.5kHz +ModeLine "1024x768" 44.9 1024 1032 1208 1264 768 768 776 817 +hsync +vsync Interlace + +# 1024x768 @ 60Hz (VESA) hsync: 48.4kHz +ModeLine "1024x768" 65.0 1024 1048 1184 1344 768 771 777 806 -hsync -vsync + +# 1024x768 @ 70Hz (VESA) hsync: 56.5kHz +ModeLine "1024x768" 75.0 1024 1048 1184 1328 768 771 777 806 -hsync -vsync + +# 1024x768 @ 75Hz (VESA) hsync: 60.0kHz +ModeLine "1024x768" 78.75 1024 1040 1136 1312 768 769 772 800 +hsync +vsync + +# 1024x768 @ 85Hz (VESA) hsync: 68.7kHz +ModeLine "1024x768" 94.5 1024 1072 1168 1376 768 769 772 808 +hsync +vsync + +# 1024x768 @ 89Hz (non-standard) hsync: 72.0kHz +ModeLine "1024x768" 100 1024 1108 1280 1408 768 768 780 796 +hsync +vsync + +# 1152x864 @ 75Hz (VESA) hsync: 67.5kHz +ModeLine "1152x864" 108.0 1152 1216 1344 1600 864 865 868 900 +hsync +vsync + +# 1280x768 @ 75Hz (non-standard) hsync: 60.6kHz +ModeLine "1280x768" 105.64 1280 1312 1712 1744 768 782 792 807 -hsync +vsync + +# 1280x960 @ 60Hz (VESA) hsync: 60.0kHz +ModeLine "1280x960" 108.0 1280 1376 1488 1800 960 961 964 1000 +hsync +vsync + +# 1280x960 @ 85Hz (VESA) hsync: 85.9kHz +ModeLine "1280x960" 148.5 1280 1344 1504 1728 960 961 964 1011 +hsync +vsync + +# 1280x1024 @ 60Hz (VESA) hsync: 64.0kHz +ModeLine "1280x1024" 108.0 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync + +# 1280x1024 @ 70Hz (non-standard) hsync: 74.0kHz +ModeLine "1280x1024" 126.0 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync + +# 1280x1024 @ 75Hz (VESA) hsync: 80.0kHz +ModeLine "1280x1024" 135.0 1280 1296 1440 1688 1024 1025 1028 1066 +hsync +vsync + +# 1280x1024 @ 85Hz (VESA) hsync: 91.1kHz +ModeLine "1280x1024" 157.5 1280 1344 1504 1728 1024 1025 1028 1072 +hsync +vsync + +# 1600x1200 @ 60Hz (VESA) hsync: 75.0kHz +ModeLine "1600x1200" 162.0 1600 1664 1856 2160 1200 1201 1204 1250 +hsync +vsync + +# 1600x1200 @ 65Hz (VESA) hsync: 81.3kHz +ModeLine "1600x1200" 175.5 1600 1664 1856 2160 1200 1201 1204 1250 +hsync +vsync + +# 1600x1200 @ 70Hz (VESA) hsync: 87.5kHz +ModeLine "1600x1200" 189.0 1600 1664 1856 2160 1200 1201 1204 1250 +hsync +vsync + +# 1600x1200 @ 75Hz (VESA) hsync: 93.8kHz +ModeLine "1600x1200" 202.5 1600 1664 1856 2160 1200 1201 1204 1250 +hsync +vsync + +# 1600x1200 @ 85Hz (VESA) hsync: 106.3kHz +ModeLine "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +hsync +vsync + +# 1680x1050 @ 60.00Hz (GTF) hsync: 65.22 kHz; pclk: 147.14 MHz +ModeLine "1680x1050" 147.14 1680 1784 1968 2256 1050 1051 1054 1087 +hsync +vsync + +# 1792x1344 @ 60Hz (VESA) hsync: 83.6kHz +ModeLine "1792x1344" 204.8 1792 1920 2120 2448 1344 1345 1348 1394 -hsync +vsync + +# 1792x1344 @ 75Hz (VESA) hsync: 106.3kHz +ModeLine "1792x1344" 261.0 1792 1888 2104 2456 1344 1345 1348 1417 -hsync +vsync + +# 1856x1392 @ 60Hz (VESA) hsync: 86.3kHz +ModeLine "1856x1392" 218.3 1856 1952 2176 2528 1392 1393 1396 1439 -hsync +vsync + +# 1856x1392 @ 75Hz (VESA) hsync: 112.5kHz +ModeLine "1856x1392" 288.0 1856 1984 2208 2560 1392 1393 1396 1500 -hsync +vsync + +# 1920x1440 @ 60Hz (VESA) hsync: 90.0kHz +ModeLine "1920x1440" 234.0 1920 2048 2256 2600 1440 1441 1444 1500 -hsync +vsync + +# 1920x1440 @ 75Hz (VESA) hsync: 112.5kHz +ModeLine "1920x1440" 297.0 1920 2064 2288 2640 1440 1441 1444 1500 -hsync +vsync + + +// +// Extra modes to include as default modes in the X server. +// +// $XFree86: xc/programs/Xserver/hw/xfree86/etc/extramodes,v 1.5 2002/06/05 19:43:05 dawes Exp $ +// + +# 832x624 @ 75Hz (74.55Hz) (fix if the official/Apple spec is different) hsync: 49.725kHz +ModeLine "832x624" 57.284 832 864 928 1152 624 625 628 667 -Hsync -Vsync + +# 1152x768 @ 54.8Hz (Titanium PowerBook) hsync: 44.2kHz +ModeLine "1152x768" 64.995 1152 1178 1314 1472 768 771 777 806 +hsync +vsync + +# 1400x1050 @ 60Hz (VESA GTF) hsync: 65.5kHz +ModeLine "1400x1050" 122.0 1400 1488 1640 1880 1050 1052 1064 1082 +hsync +vsync + +# 1400x1050 @ 75Hz (VESA GTF) hsync: 82.2kHz +ModeLine "1400x1050" 155.8 1400 1464 1784 1912 1050 1052 1064 1090 +hsync +vsync + +# 1600x1024 @ 60Hz (SGI 1600SW) hsync: 64.0kHz +Modeline "1600x1024" 106.910 1600 1620 1640 1670 1024 1027 1030 1067 -hsync -vsync + +# 1920x1440 @ 85Hz (VESA GTF) hsync: 128.5kHz +Modeline "1920x1440" 341.35 1920 2072 2288 2656 1440 1441 1444 1512 -hsync +vsync + +# 2048x1536 @ 60Hz (VESA GTF) hsync: 95.3kHz +Modeline "2048x1536" 266.95 2048 2200 2424 2800 1536 1537 1540 1589 -hsync +vsync + +# 2048x1536 @ 75Hz (VESA GTF) hsync: 120.2kHz +Modeline "2048x1536" 340.48 2048 2216 2440 2832 1536 1537 1540 1603 -hsync +vsync + +# 2048x1536 @ 85Hz (VESA GTF) hsync: 137.0kHz +Modeline "2048x1536" 388.04 2048 2216 2440 2832 1536 1537 1540 1612 -hsync +vsync + +// +// some Sun-specific modes +// + +# 1152x900 @ 66Hz - default on most SBus graphics devices +ModeLine "1152x900" 94.50 1152 1192 1320 1528 900 902 906 937 -hsync -vsync + +# 1152x900 @ 76Hz +ModeLine "1152x900" 105.56 1152 1168 1280 1472 900 902 906 943 -hsync -vsync diff --git a/sys/dev/videomode/modelines2c.awk b/sys/dev/videomode/modelines2c.awk new file mode 100644 index 000000000..e4d15dace --- /dev/null +++ b/sys/dev/videomode/modelines2c.awk @@ -0,0 +1,149 @@ +#! /usr/bin/awk -f +# $NetBSD: modelines2c.awk,v 1.5 2011/03/21 19:32:26 jdc Exp $ +# +# Copyright (c) 2006 Itronix Inc. +# All rights reserved. +# +# Written by Garrett D'Amore for Itronix Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of Itronix Inc. may not be used to endorse +# or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +BEGIN { + nmodes = 0; +} + +NR == 1 { + split($0,v,"$"); + + VERSION=v[2]; + + printf("/*\t$NetBSD" "$\t*/\n\n"); + printf("/*\n") ; + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n"); + printf(" *\n"); + printf(" * generated from:\n"); + printf(" *\t%s\n", VERSION); + printf(" */\n\n"); + + printf("#include \n"); + printf("__KERNEL_RCSID(0, \"$NetBSD" "$\");\n\n"); + + printf("#include \n\n"); + + printf("/*\n"); + printf(" * These macros help the modelines below fit on one line.\n"); + printf(" */\n"); + printf("#define HP VID_PHSYNC\n"); + printf("#define HN VID_NHSYNC\n"); + printf("#define VP VID_PVSYNC\n"); + printf("#define VN VID_NVSYNC\n"); + printf("#define I VID_INTERLACE\n"); + printf("#define DS VID_DBLSCAN\n"); + printf("\n"); + + printf("#define M(nm,hr,vr,clk,hs,he,ht,vs,ve,vt,f) \\\n"); + printf("\t{ clk, hr, hs, he, ht, vr, vs, ve, vt, f, nm } \n\n"); + + printf("const struct videomode videomode_list[] = {\n"); + + next +} + +(/^ModeLine/) { + dotclock = $3; + + hdisplay = $4; + hsyncstart = $5; + hsyncend = $6; + htotal = $7; + + vdisplay = $8; + vsyncstart = $9; + vsyncend = $10; + vtotal = $11; + + macro = "MODE"; + iflag = ""; + iflags = ""; + hflags = "HP"; + vflags = "VP"; + + if ($12 ~ "^-") + hflags = "HN"; + + if ($13 ~ "^-") + vflags = "VN"; + + ifactor=1.0; + if ($14 ~ "[Ii][Nn][Tt][Ee][Rr][Ll][Aa][Cc][Ee]") { + iflag = "i"; + iflags = "|I"; + ifactor = 2.0; + } + + # We truncate the vrefresh figure, but some mode descriptions rely + # on rounding, so we can't win here. Adding an additional .1 + # compensates to some extent. + + hrefresh= (dotclock * 1000000) / htotal; + vrefresh= int(((hrefresh * ifactor) / vtotal) + .1); + + modestr = sprintf("%dx%dx%d%s", hdisplay, vdisplay, vrefresh, iflag); + +# printf("/* %dx%d%s refresh %d Hz, hsync %d kHz */\n", +# hdisplay, vdisplay, iflag, vrefresh, hrefresh/1000); + printf("M(\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%s),\n", + modestr, + hdisplay, vdisplay, dotclock * 1000, + hsyncstart, hsyncend, htotal, + vsyncstart, vsyncend, vtotal, hflags "|" vflags iflags); + + modestr = sprintf("%dx%dx%d%s", + hdisplay/2 , vdisplay/2, vrefresh, iflag); + + dmodes[nmodes]=sprintf("M(\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%s),", + modestr, + hdisplay/2, vdisplay/2, dotclock * 1000 / 2, + hsyncstart/2, hsyncend/2, htotal/2, + vsyncstart/2, vsyncend/2, vtotal/2, + hflags "|" vflags "|DS" iflags); + + nmodes = nmodes + 1 + +} + +END { + + printf("\n/* Derived Double Scan Modes */\n\n"); + + for ( i = 0; i < nmodes; i++ ) + { + print dmodes[i]; + } + + printf("};\n\n"); + printf("const int videomode_count = %d;\n", nmodes); +} diff --git a/sys/dev/videomode/pickmode.c b/sys/dev/videomode/pickmode.c new file mode 100644 index 000000000..2cd9a45b1 --- /dev/null +++ b/sys/dev/videomode/pickmode.c @@ -0,0 +1,208 @@ +/* $NetBSD: pickmode.c,v 1.4 2011/04/09 20:53:39 christos Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation + * All rights reserved. + * + * this code was contributed to The NetBSD Foundation by Michael Lorenz + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE NETBSD FOUNDATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: pickmode.c,v 1.4 2011/04/09 20:53:39 christos Exp $"); + +#include +#include +#ifndef __minix +#include "opt_videomode.h" +#endif +#ifndef abs +#define abs(x) (((x) < 0) ? -(x) : (x)) +#endif + +#ifdef PICKMODE_DEBUG +#define DPRINTF printf +#else +#define DPRINTF while (0) printf +#endif + +const struct videomode * +pick_mode_by_dotclock(int width, int height, int dotclock) +{ + const struct videomode *this, *best = NULL; + int i; + + DPRINTF("%s: looking for %d x %d at up to %d kHz\n", __func__, width, + height, dotclock); + for (i = 0; i < videomode_count; i++) { + this = &videomode_list[i]; + if ((this->hdisplay != width) || (this->vdisplay != height) || + (this->dot_clock > dotclock)) + continue; + if (best != NULL) { + if (this->dot_clock > best->dot_clock) + best = this; + } else + best = this; + } + if (best != NULL) + DPRINTF("found %s\n", best->name); + + return best; +} + +const struct videomode * +pick_mode_by_ref(int width, int height, int refresh) +{ + const struct videomode *this, *best = NULL; + int mref, closest = 1000, i, diff; + + DPRINTF("%s: looking for %d x %d at up to %d Hz\n", __func__, width, + height, refresh); + for (i = 0; i < videomode_count; i++) { + + this = &videomode_list[i]; + mref = this->dot_clock * 1000 / (this->htotal * this->vtotal); + diff = abs(mref - refresh); + if ((this->hdisplay != width) || (this->vdisplay != height)) + continue; + DPRINTF("%s in %d hz, diff %d\n", this->name, mref, diff); + if (best != NULL) { + if (diff < closest) { + best = this; + closest = diff; + } + } else { + best = this; + closest = diff; + } + } + if (best != NULL) + DPRINTF("found %s %d\n", best->name, best->dot_clock); + + return best; +} + +static inline void +swap_modes(struct videomode *left, struct videomode *right) +{ + struct videomode temp; + + temp = *left; + *left = *right; + *right = temp; +} + +/* + * Sort modes by refresh rate, aspect ratio (*), then resolution. + * Preferred mode or largest mode is first in the list and other modes + * are sorted on closest match to that mode. + * (*) Note that the aspect ratio calculation treats "close" aspect ratios + * (within 12.5%) as the same for this purpose. + */ +#define DIVIDE(x, y) (((x) + ((y) / 2)) / (y)) +void +sort_modes(struct videomode *modes, struct videomode **preferred, int nmodes) +{ + int aspect, refresh, hbest, vbest, abest, atemp, rbest, rtemp; + int i, j; + struct videomode *mtemp = NULL; + + if (nmodes < 2) + return; + + if (*preferred != NULL) { + /* Put the preferred mode first in the list */ + aspect = (*preferred)->hdisplay * 100 / (*preferred)->vdisplay; + refresh = DIVIDE(DIVIDE((*preferred)->dot_clock * 1000, + (*preferred)->htotal), (*preferred)->vtotal); + if (*preferred != modes) { + swap_modes(*preferred, modes); + *preferred = modes; + } + } else { + /* + * Find the largest horizontal and vertical mode and put that + * first in the list. Preferred refresh rate is taken from + * the first mode of this size. + */ + hbest = 0; + vbest = 0; + for (i = 0; i < nmodes; i++) { + if (modes[i].hdisplay > hbest) { + hbest = modes[i].hdisplay; + vbest = modes[i].vdisplay; + mtemp = &modes[i]; + } else if (modes[i].hdisplay == hbest && + modes[i].vdisplay > vbest) { + vbest = modes[i].vdisplay; + mtemp = &modes[i]; + } + } + aspect = mtemp->hdisplay * 100 / mtemp->vdisplay; + refresh = DIVIDE(DIVIDE(mtemp->dot_clock * 1000, + mtemp->htotal), mtemp->vtotal); + if (mtemp != modes) + swap_modes(mtemp, modes); + } + + /* Sort other modes by refresh rate, aspect ratio, then resolution */ + for (j = 1; j < nmodes - 1; j++) { + rbest = 1000; + abest = 1000; + hbest = 0; + vbest = 0; + for (i = j; i < nmodes; i++) { + rtemp = abs(refresh - + DIVIDE(DIVIDE(modes[i].dot_clock * 1000, + modes[i].htotal), modes[i].vtotal)); + atemp = (modes[i].hdisplay * 100 / modes[i].vdisplay); + if (rtemp < rbest) { + rbest = rtemp; + mtemp = &modes[i]; + } + if (rtemp == rbest) { + /* Treat "close" aspect ratios as identical */ + if (abs(abest - atemp) > (abest / 8) && + abs(aspect - atemp) < abs(aspect - abest)) { + abest = atemp; + mtemp = &modes[i]; + } + if (atemp == abest || + abs(abest - atemp) <= (abest / 8)) { + if (modes[i].hdisplay > hbest) { + hbest = modes[i].hdisplay; + mtemp = &modes[i]; + } + if (modes[i].hdisplay == hbest && + modes[i].vdisplay > vbest) { + vbest = modes[i].vdisplay; + mtemp = &modes[i]; + } + } + } + } + if (mtemp != &modes[j]) + swap_modes(mtemp, &modes[j]); + } +} diff --git a/sys/dev/videomode/test.c b/sys/dev/videomode/test.c new file mode 100644 index 000000000..21c7e4884 --- /dev/null +++ b/sys/dev/videomode/test.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include "videomode.h" + +int +main(int argc, char **argv) +{ + int i, j; + + for (i = 1; i < argc ; i++) { + for (j = 0; j < videomode_count; j++) { + if (strcmp(videomode_list[j].name, argv[i]) == 0) { + printf("dotclock for mode %s = %d, flags %x\n", + argv[i], + videomode_list[j].dot_clock, + videomode_list[j].flags); + break; + } + } + if (j == videomode_count) { + printf("dotclock for mode %s not found\n", argv[i]); + } + } +} diff --git a/sys/dev/videomode/vesagtf.c b/sys/dev/videomode/vesagtf.c new file mode 100644 index 000000000..a3fd6ac89 --- /dev/null +++ b/sys/dev/videomode/vesagtf.c @@ -0,0 +1,704 @@ +/* $NetBSD: vesagtf.c,v 1.1 2006/05/11 01:49:53 gdamore Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This was derived from a userland GTF program supplied by NVIDIA. + * NVIDIA's original boilerplate follows. + * + * Note that I have heavily modified the program for use in the EDID + * kernel code for NetBSD, including removing the use of floating + * point operations and making significant adjustments to minimize + * error propogation while operating with integer only math. + * + * This has required the use of 64-bit integers in a few places, but + * the upshot is that for a calculation of 1920x1200x85 (as an + * example), the error deviates by only ~.004% relative to the + * floating point version. This error is *well* within VESA + * tolerances. + */ + +/* + * Copyright (c) 2001, Andy Ritger aritger@nvidia.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * o Neither the name of NVIDIA nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + * + * This program is based on the Generalized Timing Formula(GTF TM) + * Standard Version: 1.0, Revision: 1.0 + * + * The GTF Document contains the following Copyright information: + * + * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards + * Association. Duplication of this document within VESA member + * companies for review purposes is permitted. All other rights + * reserved. + * + * While every precaution has been taken in the preparation + * of this standard, the Video Electronics Standards Association and + * its contributors assume no responsibility for errors or omissions, + * and make no warranties, expressed or implied, of functionality + * of suitability for any purpose. The sample code contained within + * this standard may be used without restriction. + * + * + * + * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) + * implementation of the GTF Timing Standard, is available at: + * + * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls + * + * + * + * This program takes a desired resolution and vertical refresh rate, + * and computes mode timings according to the GTF Timing Standard. + * These mode timings can then be formatted as an XFree86 modeline + * or a mode description for use by fbset(8). + * + * + * + * NOTES: + * + * The GTF allows for computation of "margins" (the visible border + * surrounding the addressable video); on most non-overscan type + * systems, the margin period is zero. I've implemented the margin + * computations but not enabled it because 1) I don't really have + * any experience with this, and 2) neither XFree86 modelines nor + * fbset fb.modes provide an obvious way for margin timings to be + * included in their mode descriptions (needs more investigation). + * + * The GTF provides for computation of interlaced mode timings; + * I've implemented the computations but not enabled them, yet. + * I should probably enable and test this at some point. + * + * + * + * TODO: + * + * o Add support for interlaced modes. + * + * o Implement the other portions of the GTF: compute mode timings + * given either the desired pixel clock or the desired horizontal + * frequency. + * + * o It would be nice if this were more general purpose to do things + * outside the scope of the GTF: like generate double scan mode + * timings, for example. + * + * o Printing digits to the right of the decimal point when the + * digits are 0 annoys me. + * + * o Error checking. + * + */ + + +#ifdef _KERNEL +#include + +__KERNEL_RCSID(0, "$NetBSD: vesagtf.c,v 1.1 2006/05/11 01:49:53 gdamore Exp $"); +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include "videomode.h" +#include "vesagtf.h" + +void print_xf86_mode(struct videomode *m); +#endif + +#define CELL_GRAN 8 /* assumed character cell granularity */ + +/* C' and M' are part of the Blanking Duty Cycle computation */ +/* + * #define C_PRIME (((C - J) * K/256.0) + J) + * #define M_PRIME (K/256.0 * M) + */ + +/* + * C' and M' multiplied by 256 to give integer math. Make sure to + * scale results using these back down, appropriately. + */ +#define C_PRIME256(p) (((p->C - p->J) * p->K) + (p->J * 256)) +#define M_PRIME256(p) (p->K * p->M) + +#define DIVIDE(x,y) (((x) + ((y) / 2)) / (y)) + +/* + * print_value() - print the result of the named computation; this is + * useful when comparing against the GTF EXCEL spreadsheet. + */ + +#ifdef GTFDEBUG + +static void +print_value(int n, const char *name, unsigned val) +{ + printf("%2d: %-27s: %u\n", n, name, val); +} +#else +#define print_value(n, name, val) +#endif + + +/* + * vert_refresh() - as defined by the GTF Timing Standard, compute the + * Stage 1 Parameters using the vertical refresh frequency. In other + * words: input a desired resolution and desired refresh rate, and + * output the GTF mode timings. + * + * XXX All the code is in place to compute interlaced modes, but I don't + * feel like testing it right now. + * + * XXX margin computations are implemented but not tested (nor used by + * XFree86 of fbset mode descriptions, from what I can tell). + */ + +void +vesagtf_mode_params(unsigned h_pixels, unsigned v_lines, unsigned freq, + struct vesagtf_params *params, int flags, struct videomode *vmp) +{ + unsigned v_field_rqd; + unsigned top_margin; + unsigned bottom_margin; + unsigned interlace; + uint64_t h_period_est; + unsigned vsync_plus_bp; + unsigned v_back_porch; + unsigned total_v_lines; + uint64_t v_field_est; + uint64_t h_period; + unsigned v_field_rate; + unsigned v_frame_rate; + unsigned left_margin; + unsigned right_margin; + unsigned total_active_pixels; + uint64_t ideal_duty_cycle; + unsigned h_blank; + unsigned total_pixels; + unsigned pixel_freq; + + unsigned h_sync; + unsigned h_front_porch; + unsigned v_odd_front_porch_lines; + +#ifdef GTFDEBUG + unsigned h_freq; +#endif + + /* 1. In order to give correct results, the number of horizontal + * pixels requested is first processed to ensure that it is divisible + * by the character size, by rounding it to the nearest character + * cell boundary: + * + * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) + */ + + h_pixels = DIVIDE(h_pixels, CELL_GRAN) * CELL_GRAN; + + print_value(1, "[H PIXELS RND]", h_pixels); + + + /* 2. If interlace is requested, the number of vertical lines assumed + * by the calculation must be halved, as the computation calculates + * the number of vertical lines per field. In either case, the + * number of lines is rounded to the nearest integer. + * + * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), + * ROUND([V LINES],0)) + */ + + v_lines = (flags & VESAGTF_FLAG_ILACE) ? DIVIDE(v_lines, 2) : v_lines; + + print_value(2, "[V LINES RND]", v_lines); + + + /* 3. Find the frame rate required: + * + * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, + * [I/P FREQ RQD]) + */ + + v_field_rqd = (flags & VESAGTF_FLAG_ILACE) ? (freq * 2) : (freq); + + print_value(3, "[V FIELD RATE RQD]", v_field_rqd); + + + /* 4. Find number of lines in Top margin: + * 5. Find number of lines in Bottom margin: + * + * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", + * ROUND(([MARGIN%]/100*[V LINES RND]),0), + * 0) + * + * Ditto for bottom margin. Note that instead of %, we use PPT, which + * is parts per thousand. This helps us with integer math. + */ + + top_margin = bottom_margin = (flags & VESAGTF_FLAG_MARGINS) ? + DIVIDE(v_lines * params->margin_ppt, 1000) : 0; + + print_value(4, "[TOP MARGIN (LINES)]", top_margin); + print_value(5, "[BOT MARGIN (LINES)]", bottom_margin); + + + /* 6. If interlace is required, then set variable [INTERLACE]=0.5: + * + * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) + * + * To make this integer friendly, we use some special hacks in step + * 7 below. Please read those comments to understand why I am using + * a whole number of 1.0 instead of 0.5 here. + */ + interlace = (flags & VESAGTF_FLAG_ILACE) ? 1 : 0; + + print_value(6, "[2*INTERLACE]", interlace); + + + /* 7. Estimate the Horizontal period + * + * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / + * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + + * [MIN PORCH RND]+[INTERLACE]) * 1000000 + * + * To make it integer friendly, we pre-multiply the 1000000 to get to + * usec. This gives us: + * + * [H PERIOD EST] = ((1000000/[V FIELD RATE RQD]) - [MIN VSYNC+BP]) / + * ([V LINES RND] + (2 * [TOP MARGIN (LINES)]) + + * [MIN PORCH RND]+[INTERLACE]) + * + * The other problem is that the interlace value is wrong. To get + * the interlace to a whole number, we multiply both the numerator and + * divisor by 2, so we can use a value of either 1 or 0 for the interlace + * factor. + * + * This gives us: + * + * [H PERIOD EST] = ((2*((1000000/[V FIELD RATE RQD]) - [MIN VSYNC+BP])) / + * (2*([V LINES RND] + (2*[TOP MARGIN (LINES)]) + + * [MIN PORCH RND]) + [2*INTERLACE])) + * + * Finally we multiply by another 1000, to get value in picosec. + * Why picosec? To minimize rounding errors. Gotta love integer + * math and error propogation. + */ + + h_period_est = DIVIDE(((DIVIDE(2000000000000ULL, v_field_rqd)) - + (2000000 * params->min_vsbp)), + ((2 * (v_lines + (2 * top_margin) + params->min_porch)) + interlace)); + + print_value(7, "[H PERIOD EST (ps)]", h_period_est); + + + /* 8. Find the number of lines in V sync + back porch: + * + * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) + * + * But recall that h_period_est is in psec. So multiply by 1000000. + */ + + vsync_plus_bp = DIVIDE(params->min_vsbp * 1000000, h_period_est); + + print_value(8, "[V SYNC+BP]", vsync_plus_bp); + + + /* 9. Find the number of lines in V back porch alone: + * + * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] + * + * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? + */ + + v_back_porch = vsync_plus_bp - params->vsync_rqd; + + print_value(9, "[V BACK PORCH]", v_back_porch); + + + /* 10. Find the total number of lines in Vertical field period: + * + * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + + * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + + * [MIN PORCH RND] + */ + + total_v_lines = v_lines + top_margin + bottom_margin + vsync_plus_bp + + interlace + params->min_porch; + + print_value(10, "[TOTAL V LINES]", total_v_lines); + + + /* 11. Estimate the Vertical field frequency: + * + * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 + * + * Again, we want to pre multiply by 10^9 to convert for nsec, thereby + * making it usable in integer math. + * + * So we get: + * + * [V FIELD RATE EST] = 1000000000 / [H PERIOD EST] / [TOTAL V LINES] + * + * This is all scaled to get the result in uHz. Again, we're trying to + * minimize error propogation. + */ + v_field_est = DIVIDE(DIVIDE(1000000000000000ULL, h_period_est), + total_v_lines); + + print_value(11, "[V FIELD RATE EST(uHz)]", v_field_est); + + + /* 12. Find the actual horizontal period: + * + * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) + */ + + h_period = DIVIDE(h_period_est * v_field_est, v_field_rqd * 1000); + + print_value(12, "[H PERIOD(ps)]", h_period); + + + /* 13. Find the actual Vertical field frequency: + * + * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 + * + * And again, we convert to nsec ahead of time, giving us: + * + * [V FIELD RATE] = 1000000 / [H PERIOD] / [TOTAL V LINES] + * + * And another rescaling back to mHz. Gotta love it. + */ + + v_field_rate = DIVIDE(1000000000000ULL, h_period * total_v_lines); + + print_value(13, "[V FIELD RATE]", v_field_rate); + + + /* 14. Find the Vertical frame frequency: + * + * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) + * + * N.B. that the result here is in mHz. + */ + + v_frame_rate = (flags & VESAGTF_FLAG_ILACE) ? + v_field_rate / 2 : v_field_rate; + + print_value(14, "[V FRAME RATE]", v_frame_rate); + + + /* 15. Find number of pixels in left margin: + * 16. Find number of pixels in right margin: + * + * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", + * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / + * [CELL GRAN RND]),0)) * [CELL GRAN RND], + * 0)) + * + * Again, we deal with margin percentages as PPT (parts per thousand). + * And the calculations for left and right are the same. + */ + + left_margin = right_margin = (flags & VESAGTF_FLAG_MARGINS) ? + DIVIDE(DIVIDE(h_pixels * params->margin_ppt, 1000), + CELL_GRAN) * CELL_GRAN : 0; + + print_value(15, "[LEFT MARGIN (PIXELS)]", left_margin); + print_value(16, "[RIGHT MARGIN (PIXELS)]", right_margin); + + + /* 17. Find total number of active pixels in image and left and right + * margins: + * + * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + + * [RIGHT MARGIN (PIXELS)] + */ + + total_active_pixels = h_pixels + left_margin + right_margin; + + print_value(17, "[TOTAL ACTIVE PIXELS]", total_active_pixels); + + + /* 18. Find the ideal blanking duty cycle from the blanking duty cycle + * equation: + * + * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) + * + * However, we have modified values for [C'] as [256*C'] and + * [M'] as [256*M']. Again the idea here is to get good scaling. + * We use 256 as the factor to make the math fast. + * + * Note that this means that we have to scale it appropriately in + * later calculations. + * + * The ending result is that our ideal_duty_cycle is 256000x larger + * than the duty cycle used by VESA. But again, this reduces error + * propogation. + */ + + ideal_duty_cycle = + ((C_PRIME256(params) * 1000) - + (M_PRIME256(params) * h_period / 1000000)); + + print_value(18, "[IDEAL DUTY CYCLE]", ideal_duty_cycle); + + + /* 19. Find the number of pixels in the blanking time to the nearest + * double character cell: + * + * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * + * [IDEAL DUTY CYCLE] / + * (100-[IDEAL DUTY CYCLE]) / + * (2*[CELL GRAN RND])), 0)) + * * (2*[CELL GRAN RND]) + * + * Of course, we adjust to make this rounding work in integer math. + */ + + h_blank = DIVIDE(DIVIDE(total_active_pixels * ideal_duty_cycle, + (256000 * 100ULL) - ideal_duty_cycle), + 2 * CELL_GRAN) * (2 * CELL_GRAN); + + print_value(19, "[H BLANK (PIXELS)]", h_blank); + + + /* 20. Find total number of pixels: + * + * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] + */ + + total_pixels = total_active_pixels + h_blank; + + print_value(20, "[TOTAL PIXELS]", total_pixels); + + + /* 21. Find pixel clock frequency: + * + * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] + * + * We calculate this in Hz rather than MHz, to get a value that + * is usable with integer math. Recall that the [H PERIOD] is in + * nsec. + */ + + pixel_freq = DIVIDE(total_pixels * 1000000, DIVIDE(h_period, 1000)); + + print_value(21, "[PIXEL FREQ]", pixel_freq); + + + /* 22. Find horizontal frequency: + * + * [H FREQ] = 1000 / [H PERIOD] + * + * I've ifdef'd this out, because we don't need it for any of + * our calculations. + * We calculate this in Hz rather than kHz, to avoid rounding + * errors. Recall that the [H PERIOD] is in usec. + */ + +#ifdef GTFDEBUG + h_freq = 1000000000 / h_period; + + print_value(22, "[H FREQ]", h_freq); +#endif + + + + /* Stage 1 computations are now complete; I should really pass + the results to another function and do the Stage 2 + computations, but I only need a few more values so I'll just + append the computations here for now */ + + + + /* 17. Find the number of pixels in the horizontal sync period: + * + * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / + * [CELL GRAN RND]),0))*[CELL GRAN RND] + * + * Rewriting for integer math: + * + * [H SYNC (PIXELS)]=(ROUND((H SYNC%] * [TOTAL PIXELS] / 100 / + * [CELL GRAN RND),0))*[CELL GRAN RND] + */ + + h_sync = DIVIDE(((params->hsync_pct * total_pixels) / 100), CELL_GRAN) * + CELL_GRAN; + + print_value(17, "[H SYNC (PIXELS)]", h_sync); + + + /* 18. Find the number of pixels in the horizontal front porch period: + * + * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] + * + * Note that h_blank is always an even number of characters (i.e. + * h_blank % (CELL_GRAN * 2) == 0) + */ + + h_front_porch = (h_blank / 2) - h_sync; + + print_value(18, "[H FRONT PORCH (PIXELS)]", h_front_porch); + + + /* 36. Find the number of lines in the odd front porch period: + * + * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) + * + * Adjusting for the fact that the interlace is scaled: + * + * [V ODD FRONT PORCH(LINES)]=(([MIN PORCH RND] * 2) + [2*INTERLACE]) / 2 + */ + + v_odd_front_porch_lines = ((2 * params->min_porch) + interlace) / 2; + + print_value(36, "[V ODD FRONT PORCH(LINES)]", v_odd_front_porch_lines); + + + /* finally, pack the results in the mode struct */ + + vmp->hsync_start = h_pixels + h_front_porch; + vmp->hsync_end = vmp->hsync_start + h_sync; + vmp->htotal = total_pixels; + vmp->hdisplay = h_pixels; + + vmp->vsync_start = v_lines + v_odd_front_porch_lines; + vmp->vsync_end = vmp->vsync_start + params->vsync_rqd; + vmp->vtotal = total_v_lines; + vmp->vdisplay = v_lines; + + vmp->dot_clock = pixel_freq; + +} + +void +vesagtf_mode(unsigned x, unsigned y, unsigned refresh, struct videomode *vmp) +{ + struct vesagtf_params params; + + params.margin_ppt = VESAGTF_MARGIN_PPT; + params.min_porch = VESAGTF_MIN_PORCH; + params.vsync_rqd = VESAGTF_VSYNC_RQD; + params.hsync_pct = VESAGTF_HSYNC_PCT; + params.min_vsbp = VESAGTF_MIN_VSBP; + params.M = VESAGTF_M; + params.C = VESAGTF_C; + params.K = VESAGTF_K; + params.J = VESAGTF_J; + + vesagtf_mode_params(x, y, refresh, ¶ms, 0, vmp); +} + +/* + * The tidbit here is so that you can compile this file as a + * standalone user program to generate X11 modelines using VESA GTF. + * This also allows for testing of the code itself, without + * necessitating a full kernel recompile. + */ + +/* print_xf86_mode() - print the XFree86 modeline, given mode timings. */ + +#ifndef __minix +#ifndef _KERNEL +void +print_xf86_mode (struct videomode *vmp) +{ + float vf, hf; + + hf = 1000.0 * vmp->dot_clock / vmp->htotal; + vf = 1.0 * hf / vmp->vtotal; + + printf("\n"); + printf(" # %dx%d @ %.2f Hz (GTF) hsync: %.2f kHz; pclk: %.2f MHz\n", + vmp->hdisplay, vmp->vdisplay, vf, hf, vmp->dot_clock / 1000.0); + + printf(" Modeline \"%dx%d_%.2f\" %.2f" + " %d %d %d %d" + " %d %d %d %d" + " -HSync +Vsync\n\n", + vmp->hdisplay, vmp->vdisplay, vf, (vmp->dot_clock / 1000.0), + vmp->hdisplay, vmp->hsync_start, vmp->hsync_end, vmp->htotal, + vmp->vdisplay, vmp->vsync_start, vmp->vsync_end, vmp->vtotal); +} + +int +main (int argc, char *argv[]) +{ + struct videomode m; + + if (argc != 4) { + printf("usage: %s x y refresh\n", argv[0]); + exit(1); + } + + vesagtf_mode(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), &m); + + print_xf86_mode(&m); + + return 0; + +} +#endif +#endif /* !__minix */ diff --git a/sys/dev/videomode/vesagtf.h b/sys/dev/videomode/vesagtf.h new file mode 100644 index 000000000..885b685c8 --- /dev/null +++ b/sys/dev/videomode/vesagtf.h @@ -0,0 +1,85 @@ +/* $NetBSD: vesagtf.h,v 1.1 2006/05/11 01:49:53 gdamore Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Garrett D'Amore for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_VIDEOMODE_VESAGTF_H +#define _DEV_VIDEOMODE_VESAGTF_H + +/* + * Use VESA GTF formula to generate a monitor mode, given resolution and + * refresh rates. + */ + +struct vesagtf_params { + unsigned margin_ppt; /* vertical margin size, percent * 10 + * think parts-per-thousand */ + unsigned min_porch; /* minimum front porch */ + unsigned vsync_rqd; /* width of vsync in lines */ + unsigned hsync_pct; /* hsync as % of total width */ + unsigned min_vsbp; /* minimum vsync + back porch (usec) */ + unsigned M; /* blanking formula gradient */ + unsigned C; /* blanking formula offset */ + unsigned K; /* blanking formula scaling factor */ + unsigned J; /* blanking formula scaling factor */ +}; + +/* + * Default values to use for params. + */ +#define VESAGTF_MARGIN_PPT 18 /* 1.8% */ +#define VESAGTF_MIN_PORCH 1 /* minimum front porch */ +#define VESAGTF_VSYNC_RQD 3 /* vsync width in lines */ +#define VESAGTF_HSYNC_PCT 8 /* width of hsync % of total line */ +#define VESAGTF_MIN_VSBP 550 /* min vsync + back porch (usec) */ +#define VESAGTF_M 600 /* blanking formula gradient */ +#define VESAGTF_C 40 /* blanking formula offset */ +#define VESAGTF_K 128 /* blanking formula scaling factor */ +#define VESAGTF_J 20 /* blanking formula scaling factor */ + +/* + * Use VESA GTF formula to generate monitor timings. Assumes default + * GTF parameters, non-interlaced, and no margins. + */ +void vesagtf_mode(unsigned x, unsigned y, unsigned refresh, + struct videomode *); + +/* + * A more complete version, in case we ever want to use alternate GTF + * parameters. EDID 1.3 allows for "secondary GTF parameters". + */ +void vesagtf_mode_params(unsigned x, unsigned y, unsigned refresh, + struct vesagtf_params *, int flags, struct videomode *); + +#define VESAGTF_FLAG_ILACE 0x0001 /* use interlace */ +#define VESAGTF_FLAG_MARGINS 0x0002 /* use margins */ + +#endif /* _DEV_VIDEOMODE_VESAGTF_H */ diff --git a/sys/dev/videomode/videomode.c b/sys/dev/videomode/videomode.c new file mode 100644 index 000000000..aa65df4f3 --- /dev/null +++ b/sys/dev/videomode/videomode.c @@ -0,0 +1,126 @@ +/* $NetBSD: videomode.c,v 1.11 2011/03/30 18:46:32 jdc Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * NetBSD: modelines,v 1.9 2011/03/30 18:45:04 jdc Exp + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: videomode.c,v 1.11 2011/03/30 18:46:32 jdc Exp $"); + +#include + +/* + * These macros help the modelines below fit on one line. + */ +#define HP VID_PHSYNC +#define HN VID_NHSYNC +#define VP VID_PVSYNC +#define VN VID_NVSYNC +#define I VID_INTERLACE +#define DS VID_DBLSCAN + +#define M(nm,hr,vr,clk,hs,he,ht,vs,ve,vt,f) \ + { clk, hr, hs, he, ht, vr, vs, ve, vt, f, nm } + +const struct videomode videomode_list[] = { +M("640x350x85",640,350,31500,672,736,832,382,385,445,HP|VN), +M("640x400x85",640,400,31500,672,736,832,401,404,445,HN|VP), +M("720x400x70",720,400,28320,738,846,900,412,414,449,HN|VP), +M("720x400x85",720,400,35500,756,828,936,401,404,446,HN|VP), +M("720x400x87",720,400,35500,738,846,900,421,423,449,HN|VN), +M("640x480x60",640,480,25175,656,752,800,490,492,525,HN|VN), +M("640x480x72",640,480,31500,664,704,832,489,492,520,HN|VN), +M("640x480x75",640,480,31500,656,720,840,481,484,500,HN|VN), +M("640x480x85",640,480,36000,696,752,832,481,484,509,HN|VN), +M("800x600x56",800,600,36000,824,896,1024,601,603,625,HP|VP), +M("800x600x60",800,600,40000,840,968,1056,601,605,628,HP|VP), +M("800x600x72",800,600,50000,856,976,1040,637,643,666,HP|VP), +M("800x600x75",800,600,49500,816,896,1056,601,604,625,HP|VP), +M("800x600x85",800,600,56250,832,896,1048,601,604,631,HP|VP), +M("1024x768x87i",1024,768,44900,1032,1208,1264,768,776,817,HP|VP|I), +M("1024x768x60",1024,768,65000,1048,1184,1344,771,777,806,HN|VN), +M("1024x768x70",1024,768,75000,1048,1184,1328,771,777,806,HN|VN), +M("1024x768x75",1024,768,78750,1040,1136,1312,769,772,800,HP|VP), +M("1024x768x85",1024,768,94500,1072,1168,1376,769,772,808,HP|VP), +M("1024x768x89",1024,768,100000,1108,1280,1408,768,780,796,HP|VP), +M("1152x864x75",1152,864,108000,1216,1344,1600,865,868,900,HP|VP), +M("1280x768x75",1280,768,105640,1312,1712,1744,782,792,807,HN|VP), +M("1280x960x60",1280,960,108000,1376,1488,1800,961,964,1000,HP|VP), +M("1280x960x85",1280,960,148500,1344,1504,1728,961,964,1011,HP|VP), +M("1280x1024x60",1280,1024,108000,1328,1440,1688,1025,1028,1066,HP|VP), +M("1280x1024x70",1280,1024,126000,1328,1440,1688,1025,1028,1066,HP|VP), +M("1280x1024x75",1280,1024,135000,1296,1440,1688,1025,1028,1066,HP|VP), +M("1280x1024x85",1280,1024,157500,1344,1504,1728,1025,1028,1072,HP|VP), +M("1600x1200x60",1600,1200,162000,1664,1856,2160,1201,1204,1250,HP|VP), +M("1600x1200x65",1600,1200,175500,1664,1856,2160,1201,1204,1250,HP|VP), +M("1600x1200x70",1600,1200,189000,1664,1856,2160,1201,1204,1250,HP|VP), +M("1600x1200x75",1600,1200,202500,1664,1856,2160,1201,1204,1250,HP|VP), +M("1600x1200x85",1600,1200,229500,1664,1856,2160,1201,1204,1250,HP|VP), +M("1680x1050x60",1680,1050,147140,1784,1968,2256,1051,1054,1087,HP|VP), +M("1792x1344x60",1792,1344,204800,1920,2120,2448,1345,1348,1394,HN|VP), +M("1792x1344x75",1792,1344,261000,1888,2104,2456,1345,1348,1417,HN|VP), +M("1856x1392x60",1856,1392,218300,1952,2176,2528,1393,1396,1439,HN|VP), +M("1856x1392x75",1856,1392,288000,1984,2208,2560,1393,1396,1500,HN|VP), +M("1920x1440x60",1920,1440,234000,2048,2256,2600,1441,1444,1500,HN|VP), +M("1920x1440x75",1920,1440,297000,2064,2288,2640,1441,1444,1500,HN|VP), +M("832x624x74",832,624,57284,864,928,1152,625,628,667,HN|VN), +M("1152x768x54",1152,768,64995,1178,1314,1472,771,777,806,HP|VP), +M("1400x1050x60",1400,1050,122000,1488,1640,1880,1052,1064,1082,HP|VP), +M("1400x1050x74",1400,1050,155800,1464,1784,1912,1052,1064,1090,HP|VP), +M("1152x900x66",1152,900,94500,1192,1320,1528,902,906,937,HN|VN), +M("1152x900x76",1152,900,105560,1168,1280,1472,902,906,943,HN|VN), + +/* Derived Double Scan Modes */ + +M("320x175x85",320,175,15750,336,368,416,191,192,222,HP|VN|DS), +M("320x200x85",320,200,15750,336,368,416,200,202,222,HN|VP|DS), +M("360x200x70",360,200,14160,369,423,450,206,207,224,HN|VP|DS), +M("360x200x85",360,200,17750,378,414,468,200,202,223,HN|VP|DS), +M("360x200x87",360,200,17750,369,423,450,210,211,224,HN|VN|DS), +M("320x240x60",320,240,12587,328,376,400,245,246,262,HN|VN|DS), +M("320x240x72",320,240,15750,332,352,416,244,246,260,HN|VN|DS), +M("320x240x75",320,240,15750,328,360,420,240,242,250,HN|VN|DS), +M("320x240x85",320,240,18000,348,376,416,240,242,254,HN|VN|DS), +M("400x300x56",400,300,18000,412,448,512,300,301,312,HP|VP|DS), +M("400x300x60",400,300,20000,420,484,528,300,302,314,HP|VP|DS), +M("400x300x72",400,300,25000,428,488,520,318,321,333,HP|VP|DS), +M("400x300x75",400,300,24750,408,448,528,300,302,312,HP|VP|DS), +M("400x300x85",400,300,28125,416,448,524,300,302,315,HP|VP|DS), +M("512x384x87i",512,384,22450,516,604,632,384,388,408,HP|VP|DS|I), +M("512x384x60",512,384,32500,524,592,672,385,388,403,HN|VN|DS), +M("512x384x70",512,384,37500,524,592,664,385,388,403,HN|VN|DS), +M("512x384x75",512,384,39375,520,568,656,384,386,400,HP|VP|DS), +M("512x384x85",512,384,47250,536,584,688,384,386,404,HP|VP|DS), +M("512x384x89",512,384,50000,554,640,704,384,390,398,HP|VP|DS), +M("576x432x75",576,432,54000,608,672,800,432,434,450,HP|VP|DS), +M("640x384x75",640,384,52820,656,856,872,391,396,403,HN|VP|DS), +M("640x480x60",640,480,54000,688,744,900,480,482,500,HP|VP|DS), +M("640x480x85",640,480,74250,672,752,864,480,482,505,HP|VP|DS), +M("640x512x60",640,512,54000,664,720,844,512,514,533,HP|VP|DS), +M("640x512x70",640,512,63000,664,720,844,512,514,533,HP|VP|DS), +M("640x512x75",640,512,67500,648,720,844,512,514,533,HP|VP|DS), +M("640x512x85",640,512,78750,672,752,864,512,514,536,HP|VP|DS), +M("800x600x60",800,600,81000,832,928,1080,600,602,625,HP|VP|DS), +M("800x600x65",800,600,87750,832,928,1080,600,602,625,HP|VP|DS), +M("800x600x70",800,600,94500,832,928,1080,600,602,625,HP|VP|DS), +M("800x600x75",800,600,101250,832,928,1080,600,602,625,HP|VP|DS), +M("800x600x85",800,600,114750,832,928,1080,600,602,625,HP|VP|DS), +M("840x525x60",840,525,73570,892,984,1128,525,527,543,HP|VP|DS), +M("896x672x60",896,672,102400,960,1060,1224,672,674,697,HN|VP|DS), +M("896x672x75",896,672,130500,944,1052,1228,672,674,708,HN|VP|DS), +M("928x696x60",928,696,109150,976,1088,1264,696,698,719,HN|VP|DS), +M("928x696x75",928,696,144000,992,1104,1280,696,698,750,HN|VP|DS), +M("960x720x60",960,720,117000,1024,1128,1300,720,722,750,HN|VP|DS), +M("960x720x75",960,720,148500,1032,1144,1320,720,722,750,HN|VP|DS), +M("416x312x74",416,312,28642,432,464,576,312,314,333,HN|VN|DS), +M("576x384x54",576,384,32497,589,657,736,385,388,403,HP|VP|DS), +M("700x525x60",700,525,61000,744,820,940,526,532,541,HP|VP|DS), +M("700x525x74",700,525,77900,732,892,956,526,532,545,HP|VP|DS), +M("576x450x66",576,450,47250,596,660,764,451,453,468,HN|VN|DS), +M("576x450x76",576,450,52780,584,640,736,451,453,471,HN|VN|DS), +}; + +const int videomode_count = 46; diff --git a/sys/dev/videomode/videomode.h b/sys/dev/videomode/videomode.h new file mode 100644 index 000000000..b44d2bdae --- /dev/null +++ b/sys/dev/videomode/videomode.h @@ -0,0 +1,73 @@ +/* $NetBSD: videomode.h,v 1.3 2011/04/09 18:22:31 jdc Exp $ */ + +/* + * Copyright (c) 2001, 2002 Bang Jun-Young + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_VIDEOMODE_H +#define _DEV_VIDEOMODE_H + +struct videomode { + int dot_clock; /* Dot clock frequency in kHz. */ + int hdisplay; + int hsync_start; + int hsync_end; + int htotal; + int vdisplay; + int vsync_start; + int vsync_end; + int vtotal; + int flags; /* Video mode flags; see below. */ + const char *name; +}; + +/* + * Video mode flags. + */ + +#define VID_PHSYNC 0x0001 +#define VID_NHSYNC 0x0002 +#define VID_PVSYNC 0x0004 +#define VID_NVSYNC 0x0008 +#define VID_INTERLACE 0x0010 +#define VID_DBLSCAN 0x0020 +#define VID_CSYNC 0x0040 +#define VID_PCSYNC 0x0080 +#define VID_NCSYNC 0x0100 +#define VID_HSKEW 0x0200 +#define VID_BCAST 0x0400 +#define VID_PIXMUX 0x1000 +#define VID_DBLCLK 0x2000 +#define VID_CLKDIV2 0x4000 + +extern const struct videomode videomode_list[]; +extern const int videomode_count; + +const struct videomode *pick_mode_by_dotclock(int, int, int); +const struct videomode *pick_mode_by_ref(int, int, int); +void sort_modes(struct videomode *, struct videomode **, int); + +#endif /* _DEV_VIDEOMODE_H */