xserver/hw/kdrive/src/kmode.c
stefan11111 c58bd67c7c kdrive: Add a comment about the existing 1280x854 mode, and add one with good timings
Signed-off-by: stefan11111 <stefan11111github@gmail.com>
2026-07-07 11:27:04 +02:00

912 lines
30 KiB
C

/*
* Copyright 1999 SuSE, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
#include <kdrive-config.h>
#include "kdrive.h"
#include <string.h>
/* If this is ever changed, update the mode list too */
static const KdMonitorTiming kdDefaultTiming =
{800, 600, 72, 50000, /* VESA 0Ah */
56, 64, 240, KdSyncPositive, /* 48.077 */
37, 23, 66, KdSyncPositive, /* 72.188 */
};
#define KD_EXTRA_TIMINGS_4 {0}, {0}, {0}, {0},
#define KD_EXTRA_TIMINGS_16 KD_EXTRA_TIMINGS_4 KD_EXTRA_TIMINGS_4 KD_EXTRA_TIMINGS_4 KD_EXTRA_TIMINGS_4
#define KD_EXTRA_TIMINGS_64 KD_EXTRA_TIMINGS_16 KD_EXTRA_TIMINGS_16 KD_EXTRA_TIMINGS_16 KD_EXTRA_TIMINGS_16
#define KD_CVT_MODES
static KdMonitorTiming kdMonitorTimings[] = {
/* H V Hz KHz */
/* FP BP BLANK POLARITY */
/* Modes are added in the following format: */
#if 0
{Hor, Ver, rate (hz), pixclock (khz), /* mode info */
hfp, hbp, hblank, hpol, (pixels) /* Hfreq (khz) */
vfb, vbp, vblank, vpol, (lines) /* Vfreq (hz) */
#endif
/* VESA modes are taken from https://glenwing.github.io/docs/VESA-DMT-1.13.pdf */
/* IPAQ modeline:
*
* Modeline "320x240" 5.7222 320 337 340 352 240 241 244 254"
*/
{320, 240, 64, 16256,
17, 12, 32, KdSyncNegative,
1, 11, 14, KdSyncNegative,
},
/* Other VESA modes */
{640, 350, 85, 31500, /* VESA 01h */
32, 96, 192, KdSyncPositive, /* 37.861 */
32, 60, 95, KdSyncNegative, /* 85.080 */
},
{640, 400, 85, 31500, /* VESA 02h */
32, 96, 192, KdSyncNegative, /* 37.861 */
1, 41, 45, KdSyncPositive, /* 85.080 */
},
/* 640x480 modes */
{640, 480, 85, 36000, /* VESA 07h */
56, 80, 192, KdSyncNegative, /* 43.269 */
1, 25, 29, KdSyncNegative, /* 85.008 */
},
{640, 480, 75, 31500, /* VESA 06h */
16, 120, 200, KdSyncNegative, /* 37.500 */
1, 16, 20, KdSyncNegative, /* 75.000 */
},
{640, 480, 72, 31500, /* VESA 05h */ /* Margins not included in porches? */
16, 120, 176, KdSyncNegative, /* 37.861 */
1, 20, 24, KdSyncNegative, /* 72.809 */
},
{640, 480, 60, 25175, /* VESA 04h, VGA */ /* Margins included in porches? */
16, 48, 160, KdSyncNegative, /* 31.469 */
10, 33, 45, KdSyncNegative, /* 59.940 */
},
/* 720x400 mode */
{720, 400, 85, 35500, /* VESA 03h */
36, 108, 216, KdSyncNegative, /* 37.927 */
1, 42, 46, KdSyncPositive, /* 85.039 */
},
/* Modeline "720x576" 29.000 720 736 800 880 576 577 580 625 */
{
720, 576, 52, 32954, /* PAL Video */
16, 80, 160, KdSyncPositive, /* 32.954 */
1, 45, 49, KdSyncPositive, /* 52.727 */
},
/* 800x600 modes */
#ifdef KD_CVT_MODES
{800, 600, 120, 73250, /* VESA 0Dh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 76.302 */
3, 29, 36, KdSyncNegative, /* 119.972 */
},
#endif
{800, 600, 85, 56250, /* VESA 0Ch */
32, 152, 248, KdSyncPositive, /* 53.674 */
1, 27, 31, KdSyncPositive, /* 85.061 */
},
{800, 600, 75, 49500, /* VESA 0Bh */
16, 160, 256, KdSyncPositive, /* 46.875 */
1, 21, 25, KdSyncPositive, /* 75.000 */
},
/* XXX DEFAULT XXX */
{800, 600, 72, 50000, /* VESA 0Ah */
56, 64, 240, KdSyncPositive, /* 48.077 */
37, 23, 66, KdSyncPositive, /* 72.188 */
},
{800, 600, 60, 40000, /* VESA 09h */
40, 88, 256, KdSyncPositive, /* 37.879 */
1, 23, 28, KdSyncPositive, /* 60.317 */
},
{800, 600, 56, 36000, /* VESA 08h */
24, 128, 224, KdSyncPositive, /* 35.156 */
1, 22, 25, KdSyncPositive, /* 56.250 */
},
/* 848x480 mode */
{848, 480, 60, 33750, /* VESA 0Eh */
16, 112, 240, KdSyncPositive, /* 31.020 */
6, 23, 37, KdSyncPositive, /* 60.000 */
},
/* 1024x768 modes */
#ifdef KD_CVT_MODES
{1024, 768, 120, 115500, /* VESA 14h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 97.551 */
3, 38, 45, KdSyncNegative, /* 119.989 */
},
#endif
{1024, 768, 85, 94500, /* VESA 13h */
48, 208, 352, KdSyncPositive, /* 68.677 */
1, 36, 40, KdSyncPositive, /* 84.997 */
},
{1024, 768, 75, 78750, /* VESA 12h */
16, 176, 288, KdSyncPositive, /* 60.023 */
1, 28, 32, KdSyncPositive, /* 75.029 */
},
{1024, 768, 70, 75000, /* VESA 11h */
24, 144, 304, KdSyncNegative, /* 56.476 */
3, 29, 38, KdSyncNegative, /* 70.069 */
},
{1024, 768, 60, 65000, /* VESA 10h */
24, 160, 320, KdSyncNegative, /* 48.363 */
3, 29, 38, KdSyncNegative, /* 60.004 */
},
#if 0 /* interlaced, non-standard */
{1024, 768, 43, 44900, /* VESA 0Fh */
8, 56, 240, KdSyncPositive, /* 35.522 */
0, 20, 24, KdSyncPositive, /* 86.957 */
#endif
/* 1152x864 mode */
{1152, 864, 75, 108000, /* VESA 15h */
64, 256, 448, KdSyncPositive, /* 67.500 */
1, 32, 36, KdSyncPositive, /* 75.000 */
},
/* 1152x900 modes */
{1152, 900, 85, 122500, /* ADDED */
48, 208, 384, KdSyncPositive, /* 79.753 */
1, 32, 38, KdSyncPositive, /* 85.024 */
},
{1152, 900, 75, 108250, /* ADDED */
32, 208, 384, KdSyncPositive, /* 70.475 */
1, 32, 38, KdSyncPositive, /* 75.133 */
},
{1152, 900, 70, 100250, /* ADDED */
32, 208, 384, KdSyncPositive, /* 65.267 */
2, 32, 38, KdSyncPositive, /* 69.581 */
},
{1152, 900, 66, 95000, /* ADDED */
32, 208, 384, KdSyncPositive, /* 61.849 */
1, 32, 38, KdSyncPositive, /* 65.937 */
},
/* 1280x720 (720p) mode */
{1280, 720, 60, 74250, /* VESA 55h */
110, 224, 370, KdSyncPositive, /* 45.000 */
5, 20, 30, KdSyncPositive, /* 60.000 */
},
/* 1280x768 modes */
#ifdef KD_CVT_MODES
{1280, 768, 120, 140250, /* VESA 1Ah */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 97.396 */
3, 35, 45, KdSyncNegative, /* 119.798 */
},
{1280, 768, 85, 117500, /* VESA 19h */ /* CVT v1 */
80, 216, 432, KdSyncNegative, /* 68.633 */
3, 31, 41, KdSyncPositive, /* 84.837 */
},
{1280, 768, 75, 102250, /* VESA 18h */ /* CVT v1 */
80, 208, 416, KdSyncNegative, /* 60.289 */
3, 27, 37, KdSyncPositive, /* 74.893 */
},
{1280, 768, 60, 68250, /* VESA 16h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 47.776 */
3, 12, 22, KdSyncNegative, /* 59.870 */
},
#endif
/* 1280x800 modes */
#ifdef KD_CVT_MODES
{1280, 800, 120, 146250, /* VESA 1Fh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 101.563 */
3, 38, 47, KdSyncNegative, /* 119.909 */
},
{1280, 800, 85, 122500, /* VESA 1Eh */ /* CVT v1 */
80, 216, 432, KdSyncNegative, /* 71.554 */
3, 34, 43, KdSyncPositive, /* 84.880 */
},
{1280, 800, 75, 106500, /* VESA 1Dh */ /* CVT v1 */
80, 208, 416, KdSyncNegative, /* 62.795 */
3, 29, 38, KdSyncPositive, /* 74.934 */
},
{1280, 800, 60, 71000, /* VESA 1Bh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 49.306 */
3, 14, 23, KdSyncNegative, /* 59.910 */
},
#endif
/* 1280x854 modes */
/* Is this mode right? pixclock and vbp don't make sense */
{1280, 854, 103, 12500, /* ADDED */
56, 16, 128, KdSyncPositive, /* 102.554 */
1, 216, 12, KdSyncPositive,
},
/* From https://www.pseudorandom.co.uk/2003/debian/tibook/ */
/**
* Section "Monitor"
* Identifier "powerbook-lcd"
* VendorName "Apple"
* ModelName "TiBook IV"
* Mode "1280x854"
* DotClock 79.816
* HTimings 1280 1296 1408 1536
* VTimings 854 855 858 866
* Flags "-HSync" "-VSync"
* EndMode
* EndSection
*/
{1280, 854, 65, 79816, /* ADDED */
16, 128, 256, KdSyncNegative,
1, 8, 12, KdSyncNegative,
},
/* 1280x960 modes */
#ifdef KD_CVT_MODES
{1280, 960, 120, 175500, /* VESA 22h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 121.875 */
3, 50, 57, KdSyncNegative, /* 119.838 */
},
#endif
{1280, 960, 85, 148500, /* VESA 21h */
64, 224, 448, KdSyncPositive, /* 85.938 */
1, 47, 51, KdSyncPositive, /* 85.002 */
},
{1280, 960, 60, 108000, /* VESA 20h */
96, 312, 520, KdSyncPositive, /* 60.000 */
1, 36, 40, KdSyncPositive, /* 60.000 */
},
/* 1280x1024 modes */
#ifdef KD_CVT_MODES
{1280, 1024, 120, 187250, /* VESA 26h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 130.035 */
3, 50, 60, KdSyncNegative, /* 119.958 */
},
#endif
{1280, 1024, 85, 157500, /* VESA 25h */
64, 224, 448, KdSyncPositive, /* 91.146 */
1, 44, 48, KdSyncPositive, /* 85.024 */
},
{1280, 1024, 75, 135000, /* VESA 24h */
16, 248, 408, KdSyncPositive, /* 79.976 */
1, 38, 42, KdSyncPositive, /* 75.025 */
},
{1280, 1024, 60, 108000, /* VESA 23h */
48, 248, 408, KdSyncPositive, /* 63.981 */
1, 38, 42, KdSyncPositive, /* 60.020 */
},
/* 1360x768 modes */
#ifdef KD_CVT_MODES
{1360, 768, 120, 148250, /* VESA 28h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 97.533 */
3, 37, 45, KdSyncNegative, /* 119.967 */
},
#endif
{1360, 768, 60, 85500, /* VESA 27h */
64, 256, 432, KdSyncPositive, /* 47.712 */
3, 18, 27, KdSyncPositive, /* 60.015 */
},
/* 1366x768 modes */
{1366, 768, 60, 72000, /* VESA 56h */
14, 64, 134, KdSyncPositive, /* 48.000 */
1, 28, 32, KdSyncPositive, /* 60.000 */
},
/* 1400x1050 modes */
#ifdef KD_CVT_MODES
{1400, 1050, 120, 208000, /* VESA 2Dh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 133.333 */
3, 55, 62, KdSyncNegative, /* 119.904 */
},
{1400, 1050, 85, 179500, /* VESA 2Ch */ /* CVT v1 */
104, 256, 512, KdSyncNegative, /* 93.881 */
3, 48, 55, KdSyncPositive, /* 84.960 */
},
{1400, 1050, 75, 156000, /* VESA 2Bh */ /* CVT v1 */
104, 248, 496, KdSyncNegative, /* 82.278 */
3, 42, 49, KdSyncPositive, /* 74.867 */
},
{1400, 1050, 60, 101000, /* VESA 29h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 64.744 */
3, 23, 30, KdSyncNegative, /* 59.948 */
},
#endif
/* 1440x900 modes */
#ifdef KD_CVT_MODES
{1440, 900, 120, 182750, /* VESA 32h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 114.219 */
3, 44, 53, KdSyncNegative, /* 119.852 */
},
{1440, 900, 85, 157000, /* VESA 31h */ /* CVT v1 */
104, 256, 512, KdSyncNegative, /* 80.430 */
3, 39, 48, KdSyncPositive, /* 84.842 */
},
{1440, 900, 75, 136750, /* VESA 30h */ /* CVT v1 */
96, 248, 496, KdSyncNegative, /* 70.635 */
3, 33, 42, KdSyncPositive, /* 74.984 */
},
{1440, 900, 60, 88750, /* VESA 2Eh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 55.469 */
3, 17, 26, KdSyncNegative, /* 59.901 */
},
#endif
/* 1600x900 mode */
{1600, 900, 60, 108000, /* VESA 53h */
24, 96, 200, KdSyncPositive, /* 60.000 */
1, 96, 100, KdSyncPositive, /* 60.000 */
},
/* 1600x1200 modes */
#ifdef KD_CVT_MODES
{1600, 1200, 120, 268250, /* VESA 38h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 152.415 */
3, 64, 71, KdSyncNegative, /* 119.917 */
},
#endif
{1600, 1200, 85, 229500, /* VESA 37h */
64, 304, 560, KdSyncPositive, /* 106.250 */
1, 46, 50, KdSyncPositive, /* 85.000 */
},
{1600, 1200, 75, 202500, /* VESA 36h */
64, 304, 560, KdSyncPositive, /* 93.750 */
1, 46, 50, KdSyncPositive, /* 75.000 */
},
{1600, 1200, 70, 189000, /* VESA 35h */
64, 304, 560, KdSyncPositive, /* 87.500 */
1, 46, 50, KdSyncPositive, /* 70.000 */
},
{1600, 1200, 65, 175500, /* VESA 34h */
64, 304, 560, KdSyncPositive, /* 81.250 */
1, 46, 50, KdSyncPositive, /* 65.000 */
},
{1600, 1200, 60, 162000, /* VESA 33h */
64, 304, 560, KdSyncPositive, /* 75.000 */
1, 46, 50, KdSyncPositive, /* 60.000 */
},
/* 1680x1050 modes */
#ifdef KD_CVT_MODES
{1680, 1050, 120, 245500, /* VESA 3Dh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 133.424 */
3, 52, 62, KdSyncNegative, /* 119.986 */
},
{1680, 1050, 85, 214750, /* VESA 3Ch */ /* CVT v1 */
128, 304, 608, KdSyncNegative, /* 93.859 */
3, 46, 55, KdSyncPositive, /* 84.941 */
},
{1680, 1050, 75, 187000, /* VESA 3Bh */ /* CVT v1 */
120, 296, 592, KdSyncNegative, /* 82.306 */
3, 40, 49, KdSyncPositive, /* 74.892 */
},
{1680, 1050, 60, 119000, /* VESA 39h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 64.674 */
3, 21, 30, KdSyncNegative, /* 59.883 */
},
#endif
/* 1792x1344 modes */
#ifdef KD_CVT_MODES
{1792, 1344, 120, 333250, /* VESA 40h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 170.722 */
3, 72, 79, KdSyncNegative, /* 119.974 */
},
#endif
{1792, 1344, 85, 301500, /* ADDED */
96, 352, 672, KdSyncNegative, /* 122.362 */
1, 92, 96, KdSyncPositive, /* 84.974 */
},
{1792, 1344, 75, 261000, /* VESA 3Fh */
96, 352, 664, KdSyncNegative, /* 106.270 */
1, 69, 73, KdSyncPositive, /* 74.997 */
},
{1792, 1344, 60, 204750, /* VESA 3Eh */
128, 328, 656, KdSyncNegative, /* 83.640 */
1, 46, 50, KdSyncPositive, /* 60.000 */
},
#if 0
{1800, 1012, 75},
{1906, 1072, 68},
#endif
/* 1856x1392 modes */
#ifdef KD_CVT_MODES
{1856, 1392, 120, 356500, /* VESA 43h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 176.835 */
3, 75, 82, KdSyncNegative, /* 119.970 */
},
#endif
{1856, 1392, 85, 330500, /* ADDED */
160, 352, 736, KdSyncNegative, /* 127.508 */
1, 104, 108, KdSyncPositive, /* 85.001 */
},
{1856, 1392, 75, 288000, /* VESA 42h */
128, 352, 704, KdSyncNegative, /* 112.500 */
1, 104, 108, KdSyncPositive, /* 75.000 */
},
{1856, 1392, 60, 218250, /* VESA 41h */
96, 352, 672, KdSyncNegative, /* 86.333 */
1, 43, 47, KdSyncPositive, /* 59.995 */
},
/* 1920x1080 (1080p) mode */
{1920, 1080, 60, 148500, /* VESA 52h */
88, 148, 280, KdSyncPositive, /* 67.500 */
4, 36, 45, KdSyncPositive, /* 60.000 */
},
/* 1920x1200 modes */
#ifdef KD_CVT_MODES
{1920, 1200, 120, 317000, /* VESA 48h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 152.404 */
3, 62, 71, KdSyncNegative, /* 119.909 */
},
{1920, 1200, 85, 281250, /* VESA 47h */ /* CVT v1 */
144, 352, 704, KdSyncNegative, /* 107.184 */
3, 53, 62, KdSyncPositive, /* 84.932 */
},
{1920, 1200, 75, 245450, /* VESA 46h */ /* CVT v1 */
136, 344, 688, KdSyncNegative, /* 94.038 */
3, 46, 55, KdSyncPositive, /* 74.930 */
},
{1920, 1200, 60, 154000, /* VESA 44h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 74.038 */
3, 26, 35, KdSyncNegative, /* 59.950 */
},
#endif
/* 1920x1440 modes */
#ifdef KD_CVT_MODES
{1920, 1440, 120, 380500, /* VESA 4Bh */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 182.933 */
3, 78, 85, KdSyncNegative, /* 119.956 */
},
{1920, 1440, 85, 341750, /* ADDED */
160, 352, 760, KdSyncNegative, /* 127.512 */
1, 56, 60, KdSyncPositive, /* 85.012 */
},
{1920, 1440, 75, 297000, /* VESA 4Ah */
144, 352, 720, KdSyncNegative, /* 112.500 */
1, 56, 60, KdSyncPositive, /* 75.000 */
},
{1920, 1440, 60, 234000, /* VESA 49h */
128, 344, 680, KdSyncNegative, /* 90.000 */
1, 56, 60, KdSyncPositive, /* 60.000 */
},
#endif
/* 2048x1152 mode */
{2048, 1152, 60, 162000, /* VESA 54h */
26, 96, 202, KdSyncPositive, /* 72.000 */
1, 44, 48, KdSyncPositive, /* 60.000 */
},
/* 2560x1600 modes */
#ifdef KD_CVT_MODES
{2560, 1600, 120, 552750, /* VESA 50h */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 203.217 */
3, 85, 94, KdSyncNegative, /* 119.963 */
},
{2560, 1600, 85, 505250, /* VESA 4Fh */ /* CVT v1 */
208, 488, 976, KdSyncNegative, /* 142.887 */
3, 73, 82, KdSyncPositive, /* 84.951 */
},
{2560, 1600, 75, 443250, /* VESA 4Eh */ /* CVT v1 */
208, 488, 976, KdSyncNegative, /* 125.354 */
3, 63, 72, KdSyncPositive, /* 74.972 */
},
{2560, 1600, 60, 268500, /* VESA 4Ch */ /* CVT v1 Reduced blanking */
48, 80, 160, KdSyncPositive, /* 98.713 */
3, 37, 46, KdSyncNegative, /* 59.972 */
},
#endif
/* 4096x2160 (4k) mode */ /* Can be used to test the CVT formula implementation */
#ifdef KD_CVT_MODES
{4096, 2160, 60, 556744, /* VESA 57h */ /* CVT v2 Reduced blanking */
8, 40, 80, KdSyncPositive, /* 133.320 */
48, 6, 62, KdSyncNegative, /* 60.000 */
},
#endif
/* Space for extra modes */
#define NUM_FREE_TIMINGS 64
KD_EXTRA_TIMINGS_64
};
#define NUM_MONITOR_TIMINGS (sizeof kdMonitorTimings/sizeof kdMonitorTimings[0])
static int kdNumFreeMonitorTimings = NUM_FREE_TIMINGS;
static int kdNumMonitorTimings = NUM_MONITOR_TIMINGS - NUM_FREE_TIMINGS;
int
KdFindRate(KdScreenInfo * screen,
Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *))
{
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < kdNumMonitorTimings; i++, t++) {
if ((*supported) (screen, t) &&
t->horizontal == screen->width &&
t->vertical == screen->height) {
return t->rate;
}
}
return 0;
}
const KdMonitorTiming *
KdFindMode(KdScreenInfo * screen,
Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *))
{
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < kdNumMonitorTimings; i++, t++) {
if ((*supported) (screen, t) &&
t->horizontal == screen->width &&
t->vertical == screen->height &&
(!screen->rate || t->rate <= screen->rate)) {
return t;
}
}
ErrorF("Warning: mode not found, using default\n");
return &kdDefaultTiming;
}
Bool
KdAddMode(const KdMonitorTiming *new)
{
int i;
KdMonitorTiming *t;
static Bool warned = FALSE;
for (i = kdNumMonitorTimings, t = kdMonitorTimings; i > 0; i--, t++) {
/* Look if the mode already exists */
if ((t->horizontal == new->horizontal) &&
(t->vertical == new->vertical) &&
(t->rate == new->rate)) {
return TRUE;
}
if (t->horizontal > new->horizontal) {
break;
}
if ((t->horizontal == new->horizontal) &&
(t->vertical > new->vertical)) {
break;
}
if ((t->horizontal == new->horizontal) &&
(t->vertical == new->vertical) &&
(t->rate < new->rate)) {
break;
}
}
if (!kdNumFreeMonitorTimings) {
if (!warned) {
ErrorF("Warning: Ran out of space for adding screen modes\n");
warned = TRUE;
}
return FALSE;
}
memmove(t + 1, t, i * sizeof(*t));
*t = *new;
kdNumFreeMonitorTimings--;
kdNumMonitorTimings++;
return TRUE;
}
/* Based on the CVT 1.2 reduced blanking formula, see https://glenwing.github.io/docs/VESA-CVT-1.2.pdf for the constants below */
static KdMonitorTiming
KdGenerateModeCVT(int width, int height, int rate)
{
KdMonitorTiming new = {0};
float hperiod;
/**
* 3.4.3 Reduced Blanking Timing Version 2
*
* The following sections describe new rules mandated by the reduced blanking timing v2. New reduced blank
* DMT timings shall use the reduced blanking timing v2 rules.
*/
/**
* 1. Pixel Clock Selection
*
* The new version shall support a resolution of 0.001MHz to produce more accurate refresh rate result
* required in some application.
* The target refresh rate is comprised of a nominal refresh rate and optionally a 1000/1001 multiplier
* factor for video optimized rates (i.e. for 59.94Hz, it has 60Hz nominal refresh rate and a 1000/1001
* factor).
*
* The following lists the steps taken to calculate the pixel clock for a given target refresh rate and
* active H/V resolution; further details are in Section 5.4.
*
* a) First the nominal refresh rate is used to calculate the horizontal and vertical blank parameters,
*
* b) then calculate horizontal and vertical blank parameter along with required H/V active with the
* target refresh rate (including 1000/1001 factor if required) is used to calculate the pixel clock.
*
* c) The result value is then rounded to nearest 0.001 pixel clock
*
* Using the nominal value in step (a) guarantees that the only difference in timing between a video
* optimized timing vs. a non-video optimized timing for a given refresh rate is in pixel clock (i.e. all
* other vertical and horizontal parameters are same).
*/
#define CVT_CLOCK_STEP 1 /* KHZ */ /* unused since the remainder when dividing by 1 is always 0 */
/**
* 2. Vertical Refresh Rate
*
* The standard refresh rate for Reduced Blanking v2 timing is 60Hz however other progressive refresh
* may be used depending on the application. Higher precision of the pixel clock step allows video
* optimized refresh rates (i.e. 60*1000/1001Hz, 30*1000/1001Hz) to be supported with the new
* version. A factor of 1000/1001 is applied to the nominal refresh rate if the video optimized target
* refresh rate is required.
*/
#define CVT_RB_DEF_RATE 60 /* HZ */
/**
* 3. Horizontal Counts
*
* As per rules of the Reduced Blanking v2 timings, Horizontal Timings may have a precision of 1
* pixel. This allows timing for resolutions like 1366x768 to be defined with the new standard. No
* longer is the Horizontal Timing, including the Horizontal Active pixels, Horizontal Total pixels, Sync
* Pulse duration and “Front Porch” and “Back Porch” times required to be divisible by eight.
*/
#define CVT_CELL_GRAN 1 /* Pixels */ /* unused since the remainder when dividing by 1 is always 0 */
/**
* 4. Horizontal Blanking Time
*
* For Reduced Blanking v2 timings, the Horizontal Blanking time will in all cases are fixed to 80 clock
* cycles instead of 160 clock cycles required by earlier Reduced Blanking Timing.
*
* 5. Horizontal Sync Pulse Duration and Position
*
* The Horizontal Sync Pulse duration will in all cases be 32 pixel clocks in duration, with the position
* set so that the trailing edge of the Horizontal Sync Pulse is located in the center of the Horizontal
* Blanking period. This implies that for a fixed blank of 80 pixel clocks, the Horizontal Back Porch is
* fixed to (80/2) 40 pixel clocks and the Horizontal Front Porch is fixed to (80-40-32) = 8 clock cycles.
*/
#define CVT_RB_HFP 8 /* Pixels */
#define CVT_RB_HBP 40 /* Pixels */
#define CVT_RB_HBLANK 80 /* Pixels */
/**
* 6. Vertical Blanking Time
*
* The Vertical Blanking shall be the first multiple of integer Horizontal Lines that exceeds the
* minimum requirement of 460 microseconds.
*/
#define CVT_RB_MIN_VBLANK 460 /* microseconds */
#define HZ2USEC(x) (1e6/(x))
/*
* 7. Vertical Sync Pulse Duration and Position
*
* Vertical Sync Pulse is fixed at 8 lines indicating timing generated based on Reduced Blanking v2
* timing rules and aspect ratio information is to be derived based on Vertical and Horizontal Active
* Timing. This will allow any new timing with non-standard aspect ratio to be supported without any
* update to the specification. The Vertical Back Porch shall in all cases be fixed to 6 lines. The Vertical
* Front Porch shall be the remainder of the Vertical Blanking Time.
*/
#define CVT_RB_VSYNC 8
#define CVT_RB_VBP 6
/* VFB and VBLANK are calulated based on the above */
/* Don't leave the front porch 0 */
#define CVT_MIN_VFPORCH 1
new.horizontal = width;
new.vertical = height;
new.rate = (rate > 0) ? rate : CVT_RB_DEF_RATE;
new.hfp = CVT_RB_HFP;
new.hbp = CVT_RB_HBP;
new.hblank = CVT_RB_HBLANK;
/* The polarities are flipped for the non-reduced blanking formula */
new.hpol = KdSyncPositive;
new.vpol = KdSyncNegative;
new.vbp = CVT_RB_VBP;
/* XXX adapted from libxcvt */
/* 8. Estimate Horizontal period. */
hperiod = ((float) (HZ2USEC(new.rate) - CVT_RB_MIN_VBLANK)) / new.vertical;
if (hperiod <= 0) {
hperiod = 1;
}
/* 9. Find number of lines in vertical blanking */
new.vblank = ((float) CVT_RB_MIN_VBLANK) / hperiod + 1;
/* 10. Check if vertical blanking is sufficient */
if (new.vblank < (CVT_MIN_VFPORCH + CVT_RB_VSYNC + CVT_RB_VBP)) {
new.vblank = CVT_MIN_VFPORCH + CVT_RB_VSYNC + CVT_RB_VBP;
}
new.vfp = new.vblank - CVT_RB_VBP - CVT_RB_VSYNC;
/* 15/13. Find pixel clock frequency (kHz for xf86) */
new.clock = (new.horizontal + CVT_RB_HBLANK) * 1000.0 / hperiod;
return new;
}
/* Generate a mode based on the reduced blanking CVT formula and add it */
Bool
KdAddModeCVT(int width, int height, int rate)
{
int i;
KdMonitorTiming *t;
KdMonitorTiming new;
for (i = kdNumMonitorTimings, t = kdMonitorTimings; i > 0; i--, t++) {
/* Look if the mode already exists */
if ((t->horizontal == width) &&
(t->vertical == height) &&
(t->rate == rate)) {
return TRUE;
}
}
new = KdGenerateModeCVT(width, height, rate);
return KdAddMode(&new);
}
static const KdMonitorTiming *
kdFindPrevSize(const KdMonitorTiming * old)
{
const KdMonitorTiming *new;
if (old == kdMonitorTimings)
return 0;
new = old;
/*
* Search for the previous size
*/
while (new != kdMonitorTimings) {
new--;
if (new->horizontal != old->horizontal ||
new->vertical != old->vertical) {
break;
}
}
#if 0
/*
* Match the refresh rate (<=)
*/
while (new != kdMonitorTimings) {
const KdMonitorTiming *prev = new - 1;
if (prev->horizontal == new->horizontal &&
prev->vertical == new->vertical && prev->rate > old->rate) {
break;
}
new--;
}
#endif
return new;
}
Bool
KdTuneMode(KdScreenInfo * screen, const KdMonitorTiming *m,
Bool (*usable) (KdScreenInfo *, const KdMonitorTiming *),
Bool (*supported) (KdScreenInfo *, const KdMonitorTiming *))
{
const KdMonitorTiming *t = m;
int depth = screen->fb.depth;
if (t) {
screen->width = t->horizontal;
screen->height = t->vertical;
screen->rate = t->rate;
}
while (!(*usable) (screen, t)) {
/*
* Fix requested depth and geometry until it works
*/
if (screen->fb.depth > 16)
screen->fb.depth = 16;
else if (screen->fb.depth > 8)
screen->fb.depth = 8;
else {
screen->fb.depth = depth;
t = kdFindPrevSize(KdFindMode(screen, supported));
if (!t)
return FALSE;
screen->width = t->horizontal;
screen->height = t->vertical;
screen->rate = t->rate;
}
}
return TRUE;
}
#ifdef RANDR
Bool
KdRandRGetInfo(ScreenPtr pScreen,
int randr,
Bool (*supported) (ScreenPtr pScreen, const KdMonitorTiming *))
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < kdNumMonitorTimings; i++, t++) {
if ((*supported) (pScreen, t)) {
RRScreenSizePtr pSize;
pSize = RRRegisterSize(pScreen,
t->horizontal,
t->vertical,
screen->width_mm, screen->height_mm);
if (!pSize)
return FALSE;
if (!RRRegisterRate(pScreen, pSize, t->rate))
return FALSE;
if (t->horizontal == screen->width &&
t->vertical == screen->height && t->rate == screen->rate)
RRSetCurrentConfig(pScreen, randr, t->rate, pSize);
}
}
return TRUE;
}
const KdMonitorTiming *
KdRandRGetTiming(ScreenPtr pScreen,
Bool (*supported) (ScreenPtr pScreen,
const KdMonitorTiming *),
int rate, RRScreenSizePtr pSize)
{
int i;
const KdMonitorTiming *t;
for (i = 0, t = kdMonitorTimings; i < kdNumMonitorTimings; i++, t++) {
if (t->horizontal == pSize->width &&
t->vertical == pSize->height &&
t->rate == rate && (*supported) (pScreen, t))
return t;
}
return 0;
}
#endif