diff --git a/Kconfig b/Kconfig index dbcf9ee9ff..c71394b1ac 100644 --- a/Kconfig +++ b/Kconfig @@ -1684,6 +1684,10 @@ menu "Audio Support" source audio/Kconfig endmenu +menu "Video Support" +source video/Kconfig +endmenu + menu "Wireless Support" source wireless/Kconfig endmenu diff --git a/include/nuttx/lcd/edid.h b/include/nuttx/lcd/edid.h index 0d0e580124..44d407a5b9 100644 --- a/include/nuttx/lcd/edid.h +++ b/include/nuttx/lcd/edid.h @@ -49,6 +49,8 @@ * Included Files ********************************************************************************************/ +#include + /******************************************************************************************** * Pre-processor Definitions ********************************************************************************************/ @@ -58,91 +60,95 @@ /* EDID data offsets ************************************************************************/ /* Bytes 0-7: Header Information */ -#define EDID_HEADER_MAGIC 0 /* Fixed header pattern: 00 FF FF FF FF FF FF 00 */ -#define EDID_HEADER_MAGIC_SIZE 8 - +#define EDID_HEADER_MAGIC_OFFSET 0 /* Fixed header pattern: 00 FF FF FF FF FF FF 00 */ +#define EDID_HEADER_MAGIC_SIZE 8 + /* Bytes 8-17: Vendor Information */ -#define EDID_VENDOR_MANUFACTURER 8 /* Encoded 3-character manufacture ID */ -#define EDID_VENDOR_MANUFACTURER_SIZE 2 /* 16-bit, big endian value */ +#define EDID_VENDOR_MANUFACTURER_OFFSET 8 /* Encoded 3-character manufacture ID */ +#define EDID_VENDOR_MANUFACTURER_SIZE 2 /* 16-bit, big endian value */ -#define EDID_VENDOR_PRODUCTCODE 10 /* Product code. 16-bit, little endian value */ -#define EDID_VENDOR_PRODUCTCODE_SIZE 2 +#define EDID_VENDOR_PRODUCTCODE_OFFSET 10 /* Product code. 16-bit, little endian value */ +#define EDID_VENDOR_PRODUCTCODE_SIZE 2 -#define EDID_VENDOR_SERIALNO 12 /* Serial number: 32-bit, little endian value */ -#define EDID_VENDOR_SERIALNO_SIZE 4 +#define EDID_VENDOR_SERIALNO_OFFSET 12 /* Serial number: 32-bit, little endian value */ +#define EDID_VENDOR_SERIALNO_SIZE 4 -#define EDID_VENDOR_WEEK 16 /* Week of manufacture or model year flag */ -#define EDID_VENDOR_YEAR 17 /* Year of manufacture (minus 1990) */ +#define EDID_VENDOR_WEEK_OFFSET 16 /* Week of manufacture or model year flag */ +#define EDID_VENDOR_YEAR_OFFSET 17 /* Year of manufacture (minus 1990) */ /* Bytes 18-19: EDID Version */ -#define EDID_VERSION_MAJOR 18 /* EDID version, usually 1 (for 1.3) */ -#define EDID_VERSION_MINOR 19 /* EDID revision, usually 3 (for 1.3) */ +#define EDID_VERSION_MAJOR_OFFSET 18 /* EDID version, usually 1 (for 1.3) */ +#define EDID_VERSION_MINOR_OFFSET 19 /* EDID revision, usually 3 (for 1.3) */ /* Bytes 20-44: Display Information */ -#define EDID_DISPLAY_INPUT 20 /* Video input parameters bitmap */ -#define EDID_DISPLAY_HSIZE 21 /* Horizontal screen size, in centimetres */ -#define EDID_DISPLAY_VSIZE 22 /* Vertical screen size, in centimetres */ -#define EDID_DISPLAY_GAMMA 23 /* Display gamma, factory default */ -#define EDID_DISPLAY_FEATURES 24 /* Support features bitmap */ +#define EDID_DISPLAY_INPUT_OFFSET 20 /* Video input parameters bitmap */ +#define EDID_DISPLAY_HSIZE_OFFSET 21 /* Horizontal screen size, in centimetres */ +#define EDID_DISPLAY_VSIZE_OFFSET 22 /* Vertical screen size, in centimetres */ +#define EDID_DISPLAY_GAMMA_OFFSET 23 /* Display gamma, factory default */ +#define EDID_DISPLAY_FEATURES_OFFSET 24 /* Support features bitmap */ /* Bytes 25-34: Chromaticity */ -#define EDID_CHROMA_RG_LOW 25 /* Red and green least-significant bits (2^9, 2^10) */ -#define EDID_CHROMA_BW_LOW 26 /* Blue and white least-significant 2 bits */ -#define EDID_CHROMA_REDX 27 /* Red x value most significant 8 bits (2^1,...,2^8) */ -#define EDID_CHROMA_REDY 28 /* Red y value most significant 8 bits */ -#define EDID_CHROMA_GREENX 29 /* Green x value most significant 8 bits */ -#define EDID_CHROMA_GREENY 30 /* Green y value most significant 8 bits */ -#define EDID_CHROMA_BLUEX 31 /* Blue x value most significant 8 bits */ -#define EDID_CHROMA_BLUEY 32 /* Blue y value most significant 8 bits */ -#define EDID_CHROMA_WHITEX 33 /* Default white point x value most significant 8 bits */ -#define EDID_CHROMA_WHITEY 34 /* Default white point y value most significant 8 bits */ +#define EDID_CHROMA_RG_LOW_OFFSET 25 /* Red and green least-significant bits (2^9, 2^10) */ +#define EDID_CHROMA_BW_LOW_OFFSET 26 /* Blue and white least-significant 2 bits */ +#define EDID_CHROMA_REDX_OFFSET 27 /* Red x value most significant 8 bits (2^1,...,2^8) */ +#define EDID_CHROMA_REDY_OFFSET 28 /* Red y value most significant 8 bits */ +#define EDID_CHROMA_GREENX_OFFSET 29 /* Green x value most significant 8 bits */ +#define EDID_CHROMA_GREENY_OFFSET 30 /* Green y value most significant 8 bits */ +#define EDID_CHROMA_BLUEX_OFFSET 31 /* Blue x value most significant 8 bits */ +#define EDID_CHROMA_BLUEY_OFFSET 32 /* Blue y value most significant 8 bits */ +#define EDID_CHROMA_WHITEX_OFFSET 33 /* Default white point x value most significant 8 bits */ +#define EDID_CHROMA_WHITEY_OFFSET 34 /* Default white point y value most significant 8 bits */ /* Bytes 35-37: Established timing bitmap */ -#define EDID_TIMING_1 35 -#define EDID_TIMING_2 36 -#define EDID_TIMING_3 37 +#define EDID_TIMING_OFFSET_1 35 +#define EDID_TIMING_OFFSET_2 36 +#define EDID_TIMING_OFFSET_3 37 /* Bytes 38-53: Standard Timing Information */ -#define EDID_STDTIMING_1 38 /* Each is size two bytes. */ -#define EDID_STDTIMING_2 40 -#define EDID_STDTIMING_3 42 -#define EDID_STDTIMING_4 44 -#define EDID_STDTIMING_5 45 -#define EDID_STDTIMING_6 48 -#define EDID_STDTIMING_7 50 -#define EDID_STDTIMING_8 52 +#define EDID_STDTIMING_OFFSET 38 /* Each is size two bytes. */ +#define EDID_STDTIMING_OFFSET_1 38 +#define EDID_STDTIMING_OFFSET_2 40 +#define EDID_STDTIMING_OFFSET_3 42 +#define EDID_STDTIMING_OFFSET_4 44 +#define EDID_STDTIMING_OFFSET_5 45 +#define EDID_STDTIMING_OFFSET_6 48 +#define EDID_STDTIMING_OFFSET_7 50 +#define EDID_STDTIMING_OFFSET_8 52 -#define EDID_STDTIMING_NUMBER 8 -#define EDID_STDTIMING_SIZE 2 +#define EDID_STDTIMING_NUMBER 8 +#define EDID_STDTIMING_SIZE 2 /* Bytes 54-125: Descriptor Blocks */ -#define EDID_DESCRIPTOR_1 54 /* Each is size 18 bytes */ -#define EDID_DESCRIPTOR_2 72 -#define EDID_DESCRIPTOR_3 90 -#define EDID_DESCRIPTOR_4 108 +#define EDID_DESCRIPTOR_OFFSET 54 /* Each is size 18 bytes */ +#define EDID_DESCRIPTOR_OFFSET_1 54 +#define EDID_DESCRIPTOR_OFFSET_2 72 +#define EDID_DESCRIPTOR_OFFSET_3 90 +#define EDID_DESCRIPTOR_OFFSET_4 108 -#define EDID_DESCRIPTOR_NUMBER 4 -#define EDID_DESCRIPTOR_SIZE 18 +#define EDID_DESCRIPTOR_NUMBER 4 +#define EDID_DESCRIPTOR_SIZE 18 /* Bits 126-127: Trailer */ -#define EDID_TRAILER_NEXTENSIONS 126 /* Number of extensions to follow */ -#define EDID_TRAILER_CHECKSUM 127 /* Checksum. Sum of all 128 bytes should equal 0 */ +#define EDID_TRAILER_NEXTENSIONS_OFFSET 126 /* Number of extensions to follow */ +#define EDID_TRAILER_CHECKSUM_OFFSET 127 /* Checksum. Sum of all 128 bytes should equal 0 */ /* EDID Bitfield Definitions ****************************************************************/ +#define EDID_MAGIC {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0} + /* Vendor Section: Manufacturer ID */ -#define EDID_VENDOR_MANUFACTURER_1(n) (((n) >> 10) & 0x3f) + 'A') -#define EDID_VENDOR_MANUFACTURER_2(n) (((n) >> 5) & 0x3f) + 'A') -#define EDID_VENDOR_MANUFACTURER_3(n) ( (n) >> 0 & 0x3f) + 'A') +#define EDID_VENDOR_MANUFACTURER_1(n) ((((n) >> 10) & 0x1f) + '@') +#define EDID_VENDOR_MANUFACTURER_2(n) ((((n) >> 5) & 0x1f) + '@') +#define EDID_VENDOR_MANUFACTURER_3(n) ((((n) >> 0) & 0x1f) + '@') /* Display Section: Display Input */ @@ -213,6 +219,45 @@ #define EDID_CHROMA_RG_LOW_RED_X_SHIFT (6) /* Bits 6-7: Red x value least-significant 2 bits */ #define EDID_CHROMA_RG_LOW_RED_X_MASK (3 << EDID_CHROMA_RG_LOW_RED_X_SHIFT) +#define EDID_CHROMA_BW_LOW_WHITE_Y_SHIFT (0) /* Bits 0-1: White y value least-significant 2 bits */ +#define EDID_CHROMA_BW_LOW_WHITE_Y_MASK (3 << EDID_CHROMA_BW_LOW_WHITE_Y_SHIFT) +#define EDID_CHROMA_BW_LOW_WHITE_X_SHIFT (2) /* Bits 2-3: White x value least-significant 2 bits */ +#define EDID_CHROMA_BW_LOW_WHITE_X_MASK (3 << EDID_CHROMA_BW_LOW_WHITE_X_SHIFT) +#define EDID_CHROMA_BW_LOW_BLUE_Y_SHIFT (4) /* Bits 4-5: Blue y value least-significant 2 bits */ +#define EDID_CHROMA_BW_LOW_BLUE_Y_MASK (3 << EDID_CHROMA_BW_LOW_BLUE_Y_SHIFT) +#define EDID_CHROMA_BW_LOW_BLUE_X_SHIFT (6) /* Bits 6-7: Blue x value least-significant 2 bits */ +#define EDID_CHROMA_BW_LOW_BLUE_X_MASK (3 << EDID_CHROMA_RG_LOW_RED_X_SHIFT) + +#define _CHLO(b,s) (((b) >> (s)) & 0x3) +#define _CHHI(b) ((b) << 2) +#define _CHHILO(p,l,s,h) (_CHLO((p)[l], s) | _CHHI((p)[h])) +#define _CHROMA(p,l,s,h) ((_CHHILO(p,l,s,h) * 1000) / 1024) + +#define EDID_CHROMA_RED_X(p) \ + (_CHROMA(p, EDID_CHROMA_RG_LOW_OFFSET, EDID_CHROMA_RG_LOW_RED_X_SHIFT, \ + EDID_CHROMA_REDX_OFFSET)) +#define EDID_CHROMA_RED_Y(p) \ + (_CHROMA(p, EDID_CHROMA_RG_LOW_OFFSET, EDID_CHROMA_RG_LOW_RED_Y_SHIFT, \ + EDID_CHROMA_REDY_OFFSET)) +#define EDID_CHROMA_GREEN_X(p) \ + (_CHROMA(p, EDID_CHROMA_RG_LOW_OFFSET, EDID_CHROMA_RG_LOW_GREEN_X_SHIFT, \ + EDID_CHROMA_GREENX_OFFSET)) +#define EDID_CHROMA_GREEN_Y(p) \ + (_CHROMA(p, EDID_CHROMA_RG_LOW_OFFSET, EDID_CHROMA_RG_LOW_GREEN_Y_SHIFT, \ + EDID_CHROMA_GREENY_OFFSET)) +#define EDID_CHROMA_BLUE_X(p) \ + (_CHROMA(p, EDID_CHROMA_BW_LOW_OFFSET, EDID_CHROMA_BW_LOW_BLUE_X_SHIFT, \ + EDID_CHROMA_BLUEX_OFFSET)) +#define EDID_CHROMA_BLUE_Y(p) \ + (_CHROMA(p, EDID_CHROMA_BW_LOW_OFFSET, EDID_CHROMA_BW_LOW_BLUE_Y_SHIFT, \ + EDID_CHROMA_BLUEY_OFFSET)) +#define EDID_CHROMA_WHITE_X(p) \ + (_CHROMA(p, EDID_CHROMA_BW_LOW_OFFSET, EDID_CHROMA_BW_LOW_WHITE_X_SHIFT, \ + EDID_CHROMA_WHITEX_OFFSET)) +#define EDID_CHROMA_WHITE_Y(p) \ + (_CHROMA(p, EDID_CHROMA_BW_LOW_OFFSET, EDID_CHROMA_BW_LOW_WHITE_Y_SHIFT, \ + EDID_CHROMA_WHITEY_OFFSET)) + /* Bytes 35-37: Established timing bitmap */ #define EDID_TIMING_1_800x600_60Hz (1 << 0) @@ -245,12 +290,17 @@ #define ASPECT_RATIO_16_9 3 /* Aspect ratio: 16:9 */ #define EDID_STDTIMING_XRES_OFFSET (0) /* Byte 0: X resolution, divided by 8, less 31 */ -#define EDID_STDTIMING_INFO_OFFSET (1) /* Byte 1: Image Aspect Ratio / Vertical Frequency */ # define EDID_STDTIMING_ASPECT_SHIFT (6) /* Bits 6-7: Image aspect ratio */ # define EDID_STDTIMING_ASPECT_MASK (3 << EDID_STDTIMING_ASPECT_SHIFT) +# define EDID_STDTIMING_ASPECT_16_10 (ASPECT_RATIO_16_10 << EDID_STDTIMING_ASPECT_SHIFT) +# define EDID_STDTIMING_ASPECT_4_3 (ASPECT_RATIO_4_3 << EDID_STDTIMING_ASPECT_SHIFT) +# define EDID_STDTIMING_ASPECT_5_4 (ASPECT_RATIO_5_4 << EDID_STDTIMING_ASPECT_SHIFT) +# define EDID_STDTIMING_ASPECT_16_9 (ASPECT_RATIO_16_9 << EDID_STDTIMING_ASPECT_SHIFT) # define EDID_STDTIMING_VFREQ_SHIFT (0) /* Bits 0-5: Vertical frequency, less 60 */ # define EDID_STDTIMING_VFREQ_MASK (0x3f << EDID_STDTIMING_VFREQ_SHIFT) +#define EDID_STDTIMING_INFO_OFFSET (1) /* Byte 1: Image Aspect Ratio / Vertical Frequency */ + /* Display Descriptor: EDID Detailed Timing Descriptor */ #define EDID_STEROMODE_FIELDSEQ_RIGHT 1 /* Field sequential, sync=1 during right (bit0=0) */ @@ -261,29 +311,29 @@ #define EDID_STEROMODE_LEFT 2 /* Left image on even lines (bit0=1) */ #define EDID_STEROMODE_SIDEBYSIDE 3 /* Side-by-side (bit0=1) */ -#define EDID_DESC_PIXCLOCK 0 /* Bytes 0-1: Pixel clock in 10 kHz units */ -#define EDID_DESC_HPIXELS_LSBITS 2 /* Byte 2: Horizontal active pixels 8 LS bits */ -#define EDID_DESC_HBLANK_LSBITS 3 /* Byte 3: Horizontal blanking pixels 8 LS bits */ -#define EDID_DESC_HMSBITS 4 /* Byte 4: Horizontal MS bits */ +#define EDID_DESC_PIXCLOCK_OFFSET 0 /* Bytes 0-1: Pixel clock in 10 kHz units */ +#define EDID_DESC_HPIXELS_LSBITS_OFFSET 2 /* Byte 2: Horizontal active pixels 8 LS bits */ +#define EDID_DESC_HBLANK_LSBITS_OFFSET 3 /* Byte 3: Horizontal blanking pixels 8 LS bits */ +#define EDID_DESC_HMSBITS_OFFSET 4 /* Byte 4: Horizontal MS bits */ # define EDID_DESC_HBLANK_MSBITS_SHIFT (0) /* Bits 0-3: Horizontal blanking pixels 4 MS bits */ -# define EDID_DESC_HBLANK_MSBITS_MASK (15 << EDID_DESC_HPIXELS_MSBITS_SHIFT) +# define EDID_DESC_HBLANK_MSBITS_MASK (15 << EDID_DESC_HBLANK_MSBITS_SHIFT) # define EDID_DESC_HPIXELS_MSBITS_SHIFT (4) /* Bits 4-7: Horizontal active pixels 4 MS bits */ # define EDID_DESC_HPIXELS_MSBITS_MASK (15 << EDID_DESC_HPIXELS_MSBITS_SHIFT) -#define EDID_DESC_VLINES_LSBITS 5 /* Byte 5: Vertical active lines 8 LS bits */ -#define EDID_DESC_VBLANK_LSBITS 6 /* Byte 6: Vertical blanking lines 8 LS bits */ -#define EDID_DESC_VMSBITS 7 /* Byte 7: Vertical MS bits */ +#define EDID_DESC_VLINES_LSBITS_OFFSET 5 /* Byte 5: Vertical active lines 8 LS bits */ +#define EDID_DESC_VBLANK_LSBITS_OFFSET 6 /* Byte 6: Vertical blanking lines 8 LS bits */ +#define EDID_DESC_VMSBITS_OFFSET 7 /* Byte 7: Vertical MS bits */ # define EDID_DESC_VBLANK_MSBITS_SHIFT (0) /* Bits 0-3: Vertical blanking lines 4 MS bits */ # define EDID_DESC_VBLANK_MSBITS_MASK (15 << EDID_DESC_VBLANK_MSBITS_SHIFT) # define EDID_DESC_VLINES_MSBITS_SHIFT (4) /* Bits 4-7: Vertical active lines 4 MS bits */ # define EDID_DESC_VLINES_MSBITS_MASK (15 << EDID_DESC_VLINES_MSBITS_SHIFT) -#define EDID_DESC_HPORCH_LSBITS 8 /* Byte 8: Horizontal front porch pixels 8 LS bits */ -#define EDID_DESC_HPW_LSBITS 9 /* Byte 9: Horizontal sync pulse width pixels 8 LS bits */ -#define EDID_DESC_VPORCH_LSBITS 10 /* Byte 10: Vertical front porch and pulsewidth LS bits */ +#define EDID_DESC_HPORCH_LSBITS_OFFSET 8 /* Byte 8: Horizontal front porch pixels 8 LS bits */ +#define EDID_DESC_HPW_LSBITS_OFFSET 9 /* Byte 9: Horizontal sync pulse width pixels 8 LS bits */ +#define EDID_DESC_VPORCH_LSBITS_OFFSET 10 /* Byte 10: Vertical front porch and pulsewidth LS bits */ # define EDID_DESC_VPW_LSBITS_SHIFT (0) /* Bits 0-3: Vertical sync pulsewidth 4 LS bits */ # define EDID_DESC_VPW_LSBITS_MASK (15 << EDID_DESC_VPW_LSBITS_SHIFT) # define EDID_DESC_VPORCH_LSBITS_SHIFT (4) /* Bits 4-7: Vertical front portch 4 LS bits */ # define EDID_DESC_VPORCH_LSBITS_MASK (15 << EDID_DESC_VPORCH_LSBITS_SHIFT) -#define EDID_DESC_PORCH_MSBITS 11 /* Byte 7: Vertical MS bits */ +#define EDID_DESC_PORCH_MSBITS_OFFSET 11 /* Byte 11: Vertical MS bits */ # define EDID_DESC_VPW_MSBITS_SHIFT (0) /* Bits 0-1: Vertical sync pulsewidth lines 2 MS bits */ # define EDID_DESC_VPW_MSBITS_MASK (3 << EDID_DESC_VPW_MSBITS_SHIFT) # define EDID_DESC_VPORCH_MSBITS_SHIFT (2) /* Bits 2-3: Vertical front porch lines 2 MS bits */ @@ -292,16 +342,16 @@ # define EDID_DESC_HPW_MSBITS_MASK (3 << EDID_DESC_HPW_MSBITS_SHIFT) # define EDID_DESC_HPORCH_MSBITS_SHIFT (6) /* Bits 6-7: Horizontal front porch pixels 2 MS bits */ # define EDID_DESC_HPORCH_MSBITS_MASK (3 << EDID_DESC_HPORCH_MSBITS_SHIFT) -#define EDID_DESC_HSIZE_LSBITS 12 /* Byte 12: Horizontal image size, mm, 8 LS bits */ -#define EDID_DESC_VSIZE_LSBITS 13 /* Byte 13: Vertical image size, mm, 8 LS bits */ -#define EDID_DESC_SIZE_MSBITS 14 /* Byte 14: Image size MS bits */ +#define EDID_DESC_HSIZE_LSBITS_OFFSET 12 /* Byte 12: Horizontal image size, mm, 8 LS bits */ +#define EDID_DESC_VSIZE_LSBITS_OFFSET 13 /* Byte 13: Vertical image size, mm, 8 LS bits */ +#define EDID_DESC_SIZE_MSBITS_OFFSET 14 /* Byte 14: Image size MS bits */ # define EDID_DESC_VSIZE_MSBITS_SHIFT (0) /* Bits 0-3: Vertical image size, mm, 4 MS bits */ # define EDID_DESC_VSIZE_MSBITS_MASK (15 << EDID_DESC_VSIZE_MSBITS_SHIFT) # define EDID_DESC_HSIZE_MSBITS_SHIFT (4) /* Bits 4-7: Horizontal image size, mm, 4 MS bits */ # define EDID_DESC_HSIZE_MSBITS_MASK (15 << EDID_DESC_HSIZE_MSBITS_SHIFT) -#define EDID_DESC_HBORDER 15 /* Byte 15: Horizontal border pixels (one side) */ -#define EDID_DESC_VBORDER 16 /* Byte 16: Vertical border lines (one side) */ -#define EDID_DESC_FEATURES 17 /* Byte 17: Features bitmap */ +#define EDID_DESC_HBORDER_OFFSET 15 /* Byte 15: Horizontal border pixels (one side) */ +#define EDID_DESC_VBORDER_OFFSET 16 /* Byte 16: Vertical border lines (one side) */ +#define EDID_DESC_FEATURES_OFFSET 17 /* Byte 17: Features bitmap */ /* If bits 5-6=00: */ # define EDID_DESC_STEREO_INTERLEAVE (1 << 0) /* Bit 0: 2-way line-interleaved or side-by-side * interleaved stereo */ @@ -320,8 +370,50 @@ # define EDID_DESC_STEREO_MASK (3 << EDID_DESC_STEREO_SHIFT) # define EDID_DESC_INTERLACED (1 << 7) /* Bit 7: Interlaced */ +/* Descriptor helpers */ + +#define _VACT_LO(p) ((p)[EDID_DESC_VLINES_LSBITS_OFFSET]) +#define _VBLK_LO(p) ((p)[EDID_DESC_VBLANK_LSBITS_OFFSET]) +#define _VACT_HI(p) (((p)[EDID_DESC_VMSBITS_OFFSET] & EDID_DESC_VLINES_MSBITS_MASK) << 4) +#define _VBLK_HI(p) (((p)[EDID_DESC_VMSBITS_OFFSET] & EDID_DESC_VBLANK_MSBITS_MASK) << 8) +#define EDID_DESC_VACTIVE(p) (_VACT_LO(p) | _VACT_HI(p)) +#define EDID_DESC_VBLANK(p) (_VBLK_LO(p) | _VBLK_HI(p)) + +#define _HACT_LO(p) ((p)[EDID_DESC_HPIXELS_LSBITS_OFFSET]) +#define _HBLK_LO(p) ((p)[EDID_DESC_HBLANK_LSBITS_OFFSET]) +#define _HACT_HI(p) (((p)[EDID_DESC_HMSBITS_OFFSET] & EDID_DESC_HPIXELS_MSBITS_SHIFT) << 4) +#define _HBLK_HI(p) (((p)[EDID_DESC_HMSBITS_OFFSET] & EDID_DESC_HBLANK_MSBITS_SHIFT) << 8) +#define EDID_DESC_HACTIVE(p) (_HACT_LO(p) | _HACT_HI(p)) +#define EDID_DESC_HBLANK(p) (_HBLK_LO(p) | _HBLK_HI(p)) + +#define _HOFF_LO(p) ((p)[EDID_DESC_HPORCH_LSBITS_OFFSET]) +#define _HWID_LO(p) ((p)[EDID_DESC_HPW_LSBITS_OFFSET]) +#define _VOFF_LO(p) ((p)[EDID_DESC_VPORCH_LSBITS_OFFSET] >> EDID_DESC_VPORCH_LSBITS_SHIFT) +#define _VWID_LO(p) ((p)[EDID_DESC_VPORCH_LSBITS_OFFSET] & EDID_DESC_VPW_LSBITS_MASK) +#define _HOFF_HI(p) (((p)[EDID_DESC_PORCH_MSBITS_OFFSET] & EDID_DESC_HPORCH_MSBITS_MASK) << 2) +#define _HWID_HI(p) (((p)[EDID_DESC_PORCH_MSBITS_OFFSET] & EDID_DESC_HPW_MSBITS_MASK) << 4) +#define _VOFF_HI(p) (((p)[EDID_DESC_PORCH_MSBITS_OFFSET] & EDID_DESC_VPORCH_MSBITS_MASK) << 2) +#define _VWID_HI(p) (((p)[EDID_DESC_PORCH_MSBITS_OFFSET] & EDID_DESC_VPW_MSBITS_MASK) << 4) +#define EDID_DESC_HSYNC_OFFSET(p) (_HOFF_LO(p) | _HOFF_HI(p)) +#define EDID_DESC_HSYNC_WIDTH(p) (_HWID_LO(p) | _HWID_HI(p)) +#define EDID_DESC_VSYNC_OFFSET(p) (_VOFF_LO(p) | _VOFF_HI(p)) +#define EDID_DESC_VSYNC_WIDTH(p) (_VWID_LO(p) | _VWID_HI(p)) + +#define _HSZ_LO(p) ((p)[EDID_DESC_HSIZE_LSBITS_OFFSET]) +#define _VSZ_LO(p) ((p)[EDID_DESC_VSIZE_LSBITS_OFFSET]) +#define _HSZ_HI(p) (((p)[EDID_DESC_SIZE_MSBITS_OFFSET] & EDID_DESC_HSIZE_MSBITS_MASK) << 4) +#define _VSZ_HI(p) (((p)[EDID_DESC_SIZE_MSBITS_OFFSET] & EDID_DESC_VSIZE_MSBITS_MASK) << 8) +#define EDID_DESC_HSIZE(p) (_HSZ_LO(p) | _HSZ_HI(p)) +#define EDID_DESC_VSIZE(p) (_VSZ_LO(p) | _VSZ_HI(p)) + /* Display Descriptor: EDID Other Monitor Descriptors */ +#define EDID_DESC_ZERO_1 0 /* Bytes 0-1: Zero=not a detailed timing descriptor */ +#define EDID_DESC_ZERO_2 2 /* Byte 2: Zero */ +#define EDID_DESC_DESCTYPE 3 /* Byte 3: Descriptor type */ +#define EDID_DESC_ZERO_3 4 /* Byte 4: Zero */ +#define EDID_DESC_INFO 5 /* Bytes 5-17: Determined by descriptor type */ + /* 0x00-0x0f: Manufacturer reserved descriptors */ #define EDID_DESCTYPE_DUMMY 0x10 /* Dummy identifier */ #define EDID_DESCTYPE_STDTIMING 0xf7 /* Additional standard timing 3 */ @@ -334,11 +426,35 @@ #define EDID_DESCTYPE_TEXT 0xfe /* Unspecified text (ASCII text) */ #define EDID_DESCTYPE_SERIALNO 0xff /* Display serial number (ASCII text) */ -#define EDID_DESC_ZERO_1 0 /* Bytes 0-1: Zero=not a detailed timing descriptor */ -#define EDID_DESC_ZERO_2 2 /* Byte 2: Zero */ -#define EDID_DESC_DESCTYPE 3 /* Byte 3: Descriptor type */ -#define EDID_DESC_ZERO_3 4 /* Byte 4: Zero */ -#define EDID_DESC_INFO 5 /* Bytes 5-17: Determined by descriptor type */ +/* 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(p) ((p)[5]) /* Hz */ +#define EDID_DESC_RANGE_MAX_VFREQ(p) ((p)[6]) /* Hz */ +#define EDID_DESC_RANGE_MIN_HFREQ(p) ((p)[7]) /* kHz */ +#define EDID_DESC_RANGE_MAX_HFREQ(p) ((p)[8]) /* kHz */ +#define EDID_DESC_RANGE_MAX_CLOCK(p) (((p)[9]) * 10) /* MHz */ +#define EDID_DESC_RANGE_HAVE_GTF2(p) (((p)[10]) == 0x02) +#define EDID_DESC_RANGE_GTF2_HFREQ(p) (((p)[12]) * 2) +#define EDID_DESC_RANGE_GTF2_C(p) (((p)[13]) / 2) +#define EDID_DESC_RANGE_GTF2_M(p) ((p)[14] + ((p)[15] << 8)) +#define EDID_DESC_RANGE_GTF2_K(p) ((p)[16]) +#define EDID_DESC_RANGE_GTF2_J(p) ((p)[17] / 2) + +#define EDID_DESC_COLOR_WHITEX(p) +#define EDID_DESC_COLOR_WHITE_INDEX_1(p) ((p)[5]) +#define EDID_DESC_COLOR_WHITEX_1(p) _CHROMA(p, 6, 2, 7) +#define EDID_DESC_COLOR_WHITEY_1(p) _CHROMA(p, 6, 0, 8) +#define EDID_DESC_COLOR_GAMMA_1(p) _GAMMA(p[9]) +#define EDID_DESC_COLOR_WHITE_INDEX_2(p) ((p)[10]) +#define EDID_DESC_COLOR_WHITEX_2(p) _CHROMA(p, 11, 2, 12) +#define EDID_DESC_COLOR_WHITEY_2(p) _CHROMA(p, 11, 0, 13) +#define EDID_DESC_COLOR_GAMMA_2(p) _GAMMA(p[14]) + +#define EDID_DESC_STD_TIMING_START_OFFSET 5 +#define EDID_DESC_STD_TIMING_COUNT_OFFSET 6 /* Extended EDID data offsets ****************************************************************/ /* To be provided */ @@ -388,16 +504,16 @@ struct edid_videomode_s { - int dotclock; /* 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 above. */ + uint32_t dotclock; /* Dot clock frequency in kHz. */ + uint16_t flags; /* Video mode flags; see above. */ + uint16_t hdisplay; + uint16_t hsync_start; + uint16_t hsync_end; + uint16_t htotal; + uint16_t vdisplay; + uint16_t vsync_start; + uint16_t vsync_end; + uint16_t vtotal; FAR const char *name; int hskew; }; @@ -433,22 +549,19 @@ struct edid_range_s struct edid_info_s { - 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_manufacturer[4]; uint8_t edid_version; uint8_t edid_revision; - int edid_year; - int edid_week; uint8_t edid_video_input; uint8_t edid_max_hsize; /* in cm */ uint8_t edid_max_vsize; /* in cm */ uint8_t edid_gamma; uint8_t edid_features; uint8_t edid_ext_block_count; + uint16_t edid_product; + uint32_t edid_serial; + int edid_year; + int edid_week; int edid_have_range; struct edid_range_s edid_range; @@ -475,8 +588,11 @@ struct edid_info_s * Input Parameters: * data - A reference to the raw EDID data * edid - The location to return the digested EDID data. - * - * + * + * Returned Value: + * Zero (OK) is returned on success; otherwise a negated errno value is returned to + * indicate the nature of the failure. + * ********************************************************************************************/ int edid_parse(FAR const uint8_t *data, FAR struct edid_info_s *edid); @@ -494,9 +610,22 @@ int edid_parse(FAR const uint8_t *data, FAR struct edid_info_s *edid); * preferred - A pointer to the pointer to the preferred mode in the list * nmodes - The number of modes in the list * + * Returned Value: + * None + * ********************************************************************************************/ -int edid_sort_modes(FAR struct edid_videomode_s *modes, - FAR struct edid_videomode_s **preferred, unsigned int nmodes); +void edid_sort_modes(FAR struct edid_videomode_s *modes, + FAR struct edid_videomode_s **preferred, unsigned int nmodes); + +/******************************************************************************************** + * Name: edid_mode_lookup + * + * Description: + * Find the video mode in a look-up table + * + ********************************************************************************************/ + +FAR const struct edid_videomode_s *edid_mode_lookup(FAR const char *name); #endif /* __INCLUDE_NUTTX_LCD_EDID_H */ diff --git a/tools/Directories.mk b/tools/Directories.mk index 7c17510789..3716371dd0 100644 --- a/tools/Directories.mk +++ b/tools/Directories.mk @@ -142,6 +142,12 @@ else OTHERDIRS += audio endif +ifeq ($(CONFIG_VIDEO),y) +NONFSDIRS += video +else +OTHERDIRS += video +endif + ifeq ($(CONFIG_WIRELESS),y) NONFSDIRS += wireless else diff --git a/tools/FlatLibs.mk b/tools/FlatLibs.mk index 0ad2cc335b..3de34f3181 100644 --- a/tools/FlatLibs.mk +++ b/tools/FlatLibs.mk @@ -118,6 +118,12 @@ ifeq ($(CONFIG_AUDIO),y) NUTTXLIBS += staging$(DELIM)libaudio$(LIBEXT) endif +# Add libraries for the Video sub-system + +ifeq ($(CONFIG_VIDEO),y) +NUTTXLIBS += staging$(DELIM)libvideo$(LIBEXT) +endif + # Add libraries for the Wireless sub-system ifeq ($(CONFIG_WIRELESS),y) diff --git a/tools/KernelLibs.mk b/tools/KernelLibs.mk index f36d8d6ce5..c3f04bb2aa 100644 --- a/tools/KernelLibs.mk +++ b/tools/KernelLibs.mk @@ -112,6 +112,12 @@ ifeq ($(CONFIG_AUDIO),y) NUTTXLIBS += staging$(DELIM)libaudio$(LIBEXT) endif +# Add libraries for the Video sub-system + +ifeq ($(CONFIG_VIDEO),y) +NUTTXLIBS += staging$(DELIM)libvideo$(LIBEXT) +endif + # Add libraries for the Wireless sub-system ifeq ($(CONFIG_WIRELESS),y) diff --git a/tools/LibTargets.mk b/tools/LibTargets.mk index 188e4fb403..7d87bcc295 100644 --- a/tools/LibTargets.mk +++ b/tools/LibTargets.mk @@ -124,6 +124,12 @@ audio$(DELIM)libaudio$(LIBEXT): context staging$(DELIM)libaudio$(LIBEXT): audio$(DELIM)libaudio$(LIBEXT) $(Q) $(call INSTALL_LIB,$<,$@) +video$(DELIM)libvideo$(LIBEXT): context + $(Q) $(MAKE) -C video TOPDIR="$(TOPDIR)" libvideo$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE) + +staging$(DELIM)libvideo$(LIBEXT): video$(DELIM)libvideo$(LIBEXT) + $(Q) $(call INSTALL_LIB,$<,$@) + wireless$(DELIM)libwireless$(LIBEXT): context $(Q) $(MAKE) -C wireless TOPDIR="$(TOPDIR)" libwireless$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE) diff --git a/tools/ProtectedLibs.mk b/tools/ProtectedLibs.mk index 4bb3d19424..c218bf5a59 100644 --- a/tools/ProtectedLibs.mk +++ b/tools/ProtectedLibs.mk @@ -119,6 +119,12 @@ ifeq ($(CONFIG_AUDIO),y) NUTTXLIBS += staging$(DELIM)libaudio$(LIBEXT) endif +# Add libraries for the Video sub-system + +ifeq ($(CONFIG_VIDEO),y) +NUTTXLIBS += staging$(DELIM)libvideo$(LIBEXT) +endif + # Add libraries for the Wireless sub-system ifeq ($(CONFIG_WIRELESS),y) diff --git a/video/Kconfig b/video/Kconfig new file mode 100644 index 0000000000..f4ec346d72 --- /dev/null +++ b/video/Kconfig @@ -0,0 +1,18 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +comment "Video subsystem" + +config VIDEO + bool "Video Support" + default n + ---help--- + Enables overall support for Video library. + +if VIDEO + +source video/edid/Kconfig + +endif # VIDEO diff --git a/video/Makefile b/video/Makefile new file mode 100644 index 0000000000..9561962de1 --- /dev/null +++ b/video/Makefile @@ -0,0 +1,80 @@ +############################################################################ +# video/Makefile +# +# Copyright (C) 2019 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. Neither the name NuttX 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 +# COPYRIGHT OWNER 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. +# +############################################################################ + +-include $(TOPDIR)/Make.defs + +ASRCS = +CSRCS = + +DEPPATH = --dep-path . +VPATH = . + +include edid/Make.defs + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +BIN = libvideo$(LIBEXT) + +all: $(BIN) +.PHONY: depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +$(BIN): $(OBJS) + $(call ARCHIVE, $@, $(OBJS)) + +.depend: Makefile $(SRCS) + $(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + $(Q) touch $@ + +depend: .depend + +clean: + $(call DELFILE, $(BIN)) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/video/edid/Kconfig b/video/edid/Kconfig new file mode 100644 index 0000000000..57e4811cad --- /dev/null +++ b/video/edid/Kconfig @@ -0,0 +1,12 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config VIDEO_EDID + bool "EDID Support" + default n + ---help--- + Enable support for managing EDID data EDID (Extended Display + Identification Data). + diff --git a/video/edid/Make.defs b/video/edid/Make.defs new file mode 100644 index 0000000000..18f98e2336 --- /dev/null +++ b/video/edid/Make.defs @@ -0,0 +1,48 @@ +############################################################################ +# video/edid/Make.defs +# +# Copyright (C) 2019 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. Neither the name Nuttx 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 +# COPYRIGHT OWNER 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. +# +############################################################################ + +ifeq ($(CONFIG_VIDEO_EDID),y) + +# Files required for EDID support + +ASRCS += +CSRCS += edid_parse.c edid_videomode.c # edid_sort.c + +# Include EDID build support + +DEPPATH += --dep-path edid +VPATH += :edid + +endif diff --git a/video/edid/edid_parse.c b/video/edid/edid_parse.c new file mode 100644 index 0000000000..a4515c15fb --- /dev/null +++ b/video/edid/edid_parse.c @@ -0,0 +1,610 @@ +/**************************************************************************** + * video/edid/edid_parse.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derives from logic in FreeBSD which has an equivalent 3-clause BSD + * license: + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DIVIDE(x,y) (((x) + ((y) / 2)) / (y)) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* These are reversed established timing order */ + +static FAR const char *g_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", +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: edid_valid + * + * Description: + * Return true if the EDID is valid + * + ****************************************************************************/ + +static bool edid_valid(FAR const uint8_t *data) +{ + static const uint8_t magic[8] = EDID_MAGIC; + int sum = 0; + int i; + + /* Verify the EDID magic number */ + + if (memcmp(data, magic, 8) != 0) + { + return false; + } + + /* Verify the EDID checksum */ + + for (i = 0; i < 128; i++) + { + sum += data[i]; + } + + if ((sum & 0xff) != 0) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Name: edid_std_timing + * + * Description: + * Parse STD timing entry + * + ****************************************************************************/ + +static bool edid_std_timing(FAR const uint8_t *stdtim, + FAR struct edid_videomode_s *mode) +{ + FAR const struct edid_videomode_s *lookup; + char name[80]; + unsigned x; + unsigned y; + unsigned f; + + if ((stdtim[0] == 1 && stdtim[1] == 1) || + (stdtim[0] == 0 && stdtim[1] == 0) || + (stdtim[0] == 0x20 && stdtim[1] == 0x20)) + { + return false; + } + + x = stdtim[EDID_STDTIMING_XRES_OFFSET]; + switch (x & EDID_STDTIMING_ASPECT_MASK) + { + case EDID_STDTIMING_ASPECT_16_10: + y = x * 10 / 16; + break; + + case EDID_STDTIMING_ASPECT_4_3: + y = x * 3 / 4; + break; + + case EDID_STDTIMING_ASPECT_5_4: + y = x * 4 / 5; + break; + + case EDID_STDTIMING_ASPECT_16_9: + default: + y = x * 9 / 16; + break; + } + + f = stdtim[EDID_STDTIMING_INFO_OFFSET]; + + /* 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(name)) != NULL) + { + *mode = *lookup; + } + else + { +#if 0 /* Not implemented */ + /* 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, mode); +#endif +# warning REVISIT: Missing logic + return false; + } + + return true; +} + +/**************************************************************************** + * Name: edid_search_mode + * + * Description: + * Check if for duplicate video modes. + * + ****************************************************************************/ + +static struct edid_videomode_s * + edid_search_mode(FAR struct edid_info_s *edid, + FAR const struct edid_videomode_s *mode) +{ + int refresh; + int i; + + refresh = DIVIDE(DIVIDE(mode->dotclock * 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].dotclock * 1000, + edid->edid_modes[i].htotal), + edid->edid_modes[i].vtotal)) + { + return &edid->edid_modes[i]; + } + } + + return NULL; +} + +/**************************************************************************** + * Name: edid_desc_timing + * + * Description: + * + ****************************************************************************/ + +static bool edid_desc_timing(FAR const uint8_t *desc, + FAR struct edid_videomode_s *mode) +{ + uint16_t hactive; + unsigned int hblank; + unsigned int hsyncwid; + unsigned int hsyncoff; + unsigned int vactive; + unsigned int vblank; + unsigned int vsyncwid; + unsigned int vsyncoff; + uint8_t flags; + + flags = desc[EDID_DESC_FEATURES_OFFSET]; + + /* We don't support stereo modes (for now) */ + + if (flags & (EDID_DESC_STEREO_MASK | EDID_DESC_STEREO_INTERLEAVE)) + { + return false; + } + + mode->dotclock = (uint16_t)desc[EDID_DESC_PIXCLOCK_OFFSET] | + ((uint16_t)desc[EDID_DESC_PIXCLOCK_OFFSET + 1] << 8); + + hactive = EDID_DESC_HACTIVE(desc); + hblank = EDID_DESC_HBLANK(desc); + hsyncwid = EDID_DESC_HSYNC_WIDTH(desc); + hsyncoff = EDID_DESC_HSYNC_OFFSET(desc); + + vactive = EDID_DESC_VACTIVE(desc); + vblank = EDID_DESC_VBLANK(desc); + vsyncwid = EDID_DESC_VSYNC_WIDTH(desc); + vsyncoff = EDID_DESC_VSYNC_OFFSET(desc); + + /* Borders are contained within the blank areas. */ + + mode->hdisplay = hactive; + mode->htotal = hactive + hblank; + mode->hsync_start = hactive + hsyncoff; + mode->hsync_end = mode->hsync_start + hsyncwid; + + mode->vdisplay = vactive; + mode->vtotal = vactive + vblank; + mode->vsync_start = vactive + vsyncoff; + mode->vsync_end = mode->vsync_start + vsyncwid; + + mode->flags = 0; + + if ((flags & EDID_DESC_INTERLACED) != 0) + { + mode->flags |= VID_INTERLACE; + } + + if ((flags & EDID_DESC_DIGITAL_HPOLARITY) != 0) + { + mode->flags |= VID_PHSYNC; + } + else + { + mode->flags |= VID_NHSYNC; + } + + if ((flags & EDID_DESC_DIGITAL_VSERRATION) != 0) + { + mode->flags |= VID_PVSYNC; + } + else + { + mode->flags |= VID_NVSYNC; + } + + return true; +} + +/**************************************************************************** + * Name: edid_block + * + * Description: + * Parse an EDID descriptor block. + * + ****************************************************************************/ + +static void edid_block(FAR struct edid_info_s *edid, FAR const uint8_t *desc) +{ + struct edid_videomode_s mode; + FAR struct edid_videomode_s *exist_mode; + uint16_t pixclk; + int i; + + /* A detailed timing descriptor with have a nonzero pixel clock */ + + pixclk = ((uint16_t)desc[EDID_DESC_PIXCLOCK_OFFSET] << 8) | + (uint16_t)desc[EDID_DESC_PIXCLOCK_OFFSET + 1]; + + if (pixclk > 0) + { + if (!edid_desc_timing(desc, &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; + } + + /* Not a detailed timing descriptor */ + + switch (desc[EDID_DESC_DESCTYPE]) + { + case EDID_DESCTYPE_SERIALNO: +#if 0 /* Not implemented */ + memcpy(edid->edid_serstr, desc + EDID_DESC_ASCII_DATA_OFFSET, + EDID_DESC_ASCII_DATA_LEN); + edid->edid_serstr[sizeof(edid->edid_serial) - 1] = 0; +#endif + break; + + case EDID_DESCTYPE_TEXT: +#if 0 /* Not implemented */ + memcpy(edid->edid_comment, desc + EDID_DESC_ASCII_DATA_OFFSET, + EDID_DESC_ASCII_DATA_LEN); + edid->edid_comment[sizeof(edid->edid_comment) - 1] = 0; +#endif + break; + + case EDID_DESCTYPE_LIMITS: + edid->edid_have_range = 1; + edid->edid_range.er_min_vfreq = EDID_DESC_RANGE_MIN_VFREQ(desc); + edid->edid_range.er_max_vfreq = EDID_DESC_RANGE_MAX_VFREQ(desc); + edid->edid_range.er_min_hfreq = EDID_DESC_RANGE_MIN_HFREQ(desc); + edid->edid_range.er_max_hfreq = EDID_DESC_RANGE_MAX_HFREQ(desc); + edid->edid_range.er_max_clock = EDID_DESC_RANGE_MAX_CLOCK(desc); + + if (!EDID_DESC_RANGE_HAVE_GTF2(desc)) + { + break; + } + + edid->edid_range.er_have_gtf2 = 1; + edid->edid_range.er_gtf2_hfreq = EDID_DESC_RANGE_GTF2_HFREQ(desc); + edid->edid_range.er_gtf2_c = EDID_DESC_RANGE_GTF2_C(desc); + edid->edid_range.er_gtf2_m = EDID_DESC_RANGE_GTF2_M(desc); + edid->edid_range.er_gtf2_j = EDID_DESC_RANGE_GTF2_J(desc); + edid->edid_range.er_gtf2_k = EDID_DESC_RANGE_GTF2_K(desc); + break; + + case EDID_DESCTYPE_NAME: +#if 0 /* Not implemented */ + /* Copy the product name into place */ + + memcpy(edid->edid_productname, + desc + EDID_DESC_ASCII_DATA_OFFSET, EDID_DESC_ASCII_DATA_LEN); +#endif + break; + + case EDID_DESCTYPE_STDTIMING_ID: + desc += EDID_DESC_STD_TIMING_START_OFFSET; + for (i = 0; i < EDID_DESC_STD_TIMING_COUNT_OFFSET; i++) + { + if (edid_std_timing(desc, &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++; + } + } + + desc += 2; + } + break; + + case EDID_DESCTYPE_WHITEPOINT: + /* XXX: not implemented yet */ + break; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: edid_parse + * + * Description: + * Given a block of raw EDID data, parse the data and convert it to the + * 'digested' form of struct edid_info_s. + * + * Input Parameters: + * data - A reference to the raw EDID data + * edid - The location to return the digested EDID data. + * + * Returned Value: + * Zero (OK) is returned on success; otherwise a negated errno value is returned to + * indicate the nature of the failure. + * + ****************************************************************************/ + +int edid_parse(FAR const uint8_t *data, FAR struct edid_info_s *edid) +{ + FAR const struct edid_videomode_s *mode; + uint16_t manufacturer; + uint16_t estmodes; + uint8_t gamma; + int i; + int max_dotclock = 0; + int mhz; + + if (!edid_valid(&data[EDID_HEADER_MAGIC_OFFSET])) + { + return -EINVAL; + } + + /* Get product identification */ + + manufacturer = (uint16_t)data[EDID_VENDOR_MANUFACTURER_OFFSET] | + ((uint16_t)data[EDID_VENDOR_MANUFACTURER_OFFSET + 1] << 8); + + edid->edid_manufacturer[0] = EDID_VENDOR_MANUFACTURER_1(manufacturer); + edid->edid_manufacturer[1] = EDID_VENDOR_MANUFACTURER_2(manufacturer); + edid->edid_manufacturer[2] = EDID_VENDOR_MANUFACTURER_3(manufacturer); + edid->edid_manufacturer[3] = 0; /* NUL terminate for convenience */ + + edid->edid_product = (uint16_t)data[EDID_VENDOR_PRODUCTCODE_OFFSET] | + ((uint16_t)data[EDID_VENDOR_PRODUCTCODE_OFFSET + 1] << 8); + + edid->edid_serial = ((uint32_t)data[EDID_VENDOR_SERIALNO_OFFSET] << 24) | + ((uint32_t)data[EDID_VENDOR_SERIALNO_OFFSET + 1] << 16) | + ((uint32_t)data[EDID_VENDOR_SERIALNO_OFFSET + 2] << 8) | + (uint32_t)data[EDID_VENDOR_SERIALNO_OFFSET + 3]; + + edid->edid_week = data[EDID_VENDOR_WEEK_OFFSET]; + edid->edid_year = data[EDID_VENDOR_YEAR_OFFSET] + 1990; + + /* Get EDID revision */ + + edid->edid_version = data[EDID_VERSION_MAJOR_OFFSET]; + edid->edid_revision = data[EDID_VERSION_MINOR_OFFSET]; + + edid->edid_video_input = data[EDID_DISPLAY_INPUT_OFFSET]; + edid->edid_max_hsize = data[EDID_DISPLAY_HSIZE_OFFSET]; + edid->edid_max_vsize = data[EDID_DISPLAY_VSIZE_OFFSET]; + + gamma = data[EDID_DISPLAY_GAMMA_OFFSET]; + edid->edid_gamma = gamma == 0xff ? 100 : gamma + 100; + edid->edid_features = data[EDID_DISPLAY_FEATURES_OFFSET]; + + edid->edid_chroma.ec_redx = EDID_CHROMA_RED_X(data); + edid->edid_chroma.ec_redy = EDID_CHROMA_RED_X(data); + edid->edid_chroma.ec_greenx = EDID_CHROMA_GREEN_X(data); + edid->edid_chroma.ec_greeny = EDID_CHROMA_GREEN_Y(data); + edid->edid_chroma.ec_bluex = EDID_CHROMA_BLUE_X(data); + edid->edid_chroma.ec_bluey = EDID_CHROMA_BLUE_Y(data); + edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITE_X(data); + edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITE_Y(data); + + edid->edid_ext_block_count = data[EDID_TRAILER_NEXTENSIONS_OFFSET]; + + /* Lookup established modes */ + + edid->edid_nmodes = 0; + edid->edid_preferred_mode = NULL; + estmodes = ((uint16_t)data[EDID_TIMING_OFFSET_1] << 8) | + (uint16_t)data[EDID_TIMING_OFFSET_2]; + + /* Iterate in established timing order */ + + for (i = 15; i >= 0; i--) + { + if (estmodes & (1 << i)) + { + mode = edid_mode_lookup(g_edid_modes[i]); + if (mode != NULL) + { + edid->edid_modes[edid->edid_nmodes] = *mode; + edid->edid_nmodes++; + } + else + { + lcdwarn("WARNING: No data for est. mode %s\n", + g_edid_modes[i]); + } + } + } + + /* Do standard timing section */ + + for (i = 0; i < EDID_STDTIMING_NUMBER; i++) + { + struct edid_videomode_s stdmode; + FAR struct edid_videomode_s *exist_mode; + + if (edid_std_timing(data + EDID_STDTIMING_OFFSET + i * 2, &stdmode)) + { + /* Does this mode already exist? */ + + exist_mode = edid_search_mode(edid, &stdmode); + if (exist_mode == NULL) + { + edid->edid_modes[edid->edid_nmodes] = stdmode; + edid->edid_nmodes++; + } + } + } + + /* Do detailed timings and descriptors */ + + for (i = 0; i < EDID_DESCRIPTOR_NUMBER; i++) + { + edid_block(edid, data + EDID_DESCRIPTOR_OFFSET + i * EDID_DESCRIPTOR_SIZE); + } + + /* 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].dotclock > max_dotclock) + { + max_dotclock = edid->edid_modes[i].dotclock; + } + } + + lcdinfo("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 OK; +} diff --git a/video/edid/edid_videomode.c b/video/edid/edid_videomode.c new file mode 100644 index 0000000000..9bd7fcbd3e --- /dev/null +++ b/video/edid/edid_videomode.c @@ -0,0 +1,201 @@ +/**************************************************************************** + * video/edid/edid_parse.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derives from logic in FreeBSD which has an equivalent 3-clause BSD + * license: + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* These macros help the mode lines 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, 0 \ + } + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct edid_videomode_s g_videomodes[] = +{ + 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), +}; + +static const int g_nvideomodes = 46; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: edid_mode_lookup + * + * Description: + * Find the video mode in a look-up table + * + ****************************************************************************/ + +FAR const struct edid_videomode_s *edid_mode_lookup(FAR const char *name) +{ + int i; + + for (i = 0; i < g_nvideomodes; i++) + { + if (strcmp(name, g_videomodes[i].name) == 0) + { + return &g_videomodes[i]; + } + } + + return NULL; +}