/* * linux/drivers/video/fbmon.c * * Copyright (C) 2002 James Simmons <[email protected]> * * Credits: * * The EDID Parser is a conglomeration from the following sources: * * 1. SciTech SNAP Graphics Architecture * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. * * 2. XFree86 4.3.0, interpret_edid.c * Copyright 1998 by Egbert Eich <[email protected]> * * 3. John Fremlin <[email protected]> and * Ani Joshi <[email protected]> * * Generalized Timing Formula is derived from: * * GTF Spreadsheet by Andy Morrish (1/5/97) * available at https://www.vesa.org * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. * */ #include <linux/fb.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> #include <video/edid.h> #include <video/of_videomode.h> #include <video/videomode.h> #include "../edid.h" /* * EDID parser */ #undef DEBUG /* define this for verbose EDID parsing output */ #ifdef DEBUG #define DPRINTK … #else #define DPRINTK(fmt, args...) … #endif #define FBMON_FIX_HEADER … #define FBMON_FIX_INPUT … #define FBMON_FIX_TIMINGS … #ifdef CONFIG_FB_MODE_HELPERS struct broken_edid { … }; static const struct broken_edid brokendb[] = …; static const unsigned char edid_v1_header[] = …; static void copy_string(unsigned char *c, unsigned char *s) { … } static int edid_is_serial_block(unsigned char *block) { … } static int edid_is_ascii_block(unsigned char *block) { … } static int edid_is_limits_block(unsigned char *block) { … } static int edid_is_monitor_block(unsigned char *block) { … } static int edid_is_timing_block(unsigned char *block) { … } static int check_edid(unsigned char *edid) { … } static void fix_edid(unsigned char *edid, int fix) { … } static int edid_checksum(unsigned char *edid) { … } static int edid_check_header(unsigned char *edid) { … } static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs) { … } static void get_dpms_capabilities(unsigned char flags, struct fb_monspecs *specs) { … } static void get_chroma(unsigned char *block, struct fb_monspecs *specs) { … } static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) { … } static int get_est_timing(unsigned char *block, struct fb_videomode *mode) { … } static int get_std_timing(unsigned char *block, struct fb_videomode *mode, int ver, int rev, const struct fb_monspecs *specs) { … } static int get_dst_timing(unsigned char *block, struct fb_videomode *mode, int ver, int rev, const struct fb_monspecs *specs) { … } static void get_detailed_timing(unsigned char *block, struct fb_videomode *mode) { … } /** * fb_create_modedb - create video mode database * @edid: EDID data * @dbsize: database size * @specs: monitor specifications, may be NULL * * RETURNS: struct fb_videomode, @dbsize contains length of database * * DESCRIPTION: * This function builds a mode database using the contents of the EDID * data */ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize, const struct fb_monspecs *specs) { … } /** * fb_destroy_modedb - destroys mode database * @modedb: mode database to destroy * * DESCRIPTION: * Destroy mode database created by fb_create_modedb */ void fb_destroy_modedb(struct fb_videomode *modedb) { … } static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) { … } static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) { … } int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) { … } void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { … } /* * VESA Generalized Timing Formula (GTF) */ #define FLYBACK … #define V_FRONTPORCH … #define H_OFFSET … #define H_SCALEFACTOR … #define H_BLANKSCALE … #define H_GRADIENT … #define C_VAL … #define M_VAL … struct __fb_timings { … }; /** * fb_get_vblank - get vertical blank time * @hfreq: horizontal freq * * DESCRIPTION: * vblank = right_margin + vsync_len + left_margin * * given: right_margin = 1 (V_FRONTPORCH) * vsync_len = 3 * flyback = 550 * * flyback * hfreq * left_margin = --------------- - vsync_len * 1000000 */ static u32 fb_get_vblank(u32 hfreq) { … } /** * fb_get_hblank_by_hfreq - get horizontal blank time given hfreq * @hfreq: horizontal freq * @xres: horizontal resolution in pixels * * DESCRIPTION: * * xres * duty_cycle * hblank = ------------------ * 100 - duty_cycle * * duty cycle = percent of htotal assigned to inactive display * duty cycle = C - (M/Hfreq) * * where: C = ((offset - scale factor) * blank_scale) * -------------------------------------- + scale factor * 256 * M = blank_scale * gradient * */ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) { … } /** * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock * @dclk: pixelclock in Hz * @xres: horizontal resolution in pixels * * DESCRIPTION: * * xres * duty_cycle * hblank = ------------------ * 100 - duty_cycle * * duty cycle = percent of htotal assigned to inactive display * duty cycle = C - (M * h_period) * * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100 * ----------------------------------------------- * 2 * M * M = 300; * C = 30; */ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) { … } /** * fb_get_hfreq - estimate hsync * @vfreq: vertical refresh rate * @yres: vertical resolution * * DESCRIPTION: * * (yres + front_port) * vfreq * 1000000 * hfreq = ------------------------------------- * (1000000 - (vfreq * FLYBACK) * */ static u32 fb_get_hfreq(u32 vfreq, u32 yres) { … } static void fb_timings_vfreq(struct __fb_timings *timings) { … } static void fb_timings_hfreq(struct __fb_timings *timings) { … } static void fb_timings_dclk(struct __fb_timings *timings) { … } /* * fb_get_mode - calculates video mode using VESA GTF * @flags: if: 0 - maximize vertical refresh rate * 1 - vrefresh-driven calculation; * 2 - hscan-driven calculation; * 3 - pixelclock-driven calculation; * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock * @var: pointer to fb_var_screeninfo * @info: pointer to fb_info * * DESCRIPTION: * Calculates video mode based on monitor specs using VESA GTF. * The GTF is best for VESA GTF compliant monitors but is * specifically formulated to work for older monitors as well. * * If @flag==0, the function will attempt to maximize the * refresh rate. Otherwise, it will calculate timings based on * the flag and accompanying value. * * If FB_IGNOREMON bit is set in @flags, monitor specs will be * ignored and @var will be filled with the calculated timings. * * All calculations are based on the VESA GTF Spreadsheet * available at VESA's public ftp (https://www.vesa.org). * * NOTES: * The timings generated by the GTF will be different from VESA * DMT. It might be a good idea to keep a table of standard * VESA modes as well. The GTF may also not work for some displays, * such as, and especially, analog TV. * * REQUIRES: * A valid info->monspecs, otherwise 'safe numbers' will be used. */ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) { … } #ifdef CONFIG_VIDEOMODE_HELPERS int fb_videomode_from_videomode(const struct videomode *vm, struct fb_videomode *fbmode) { … } EXPORT_SYMBOL_GPL(…); #ifdef CONFIG_OF static inline void dump_fb_videomode(const struct fb_videomode *m) { … } /** * of_get_fb_videomode - get a fb_videomode from devicetree * @np: device_node with the timing specification * @fb: will be set to the return value * @index: index into the list of display timings in devicetree * * DESCRIPTION: * This function is expensive and should only be used, if only one mode is to be * read from DT. To get multiple modes start with of_get_display_timings ond * work with that instead. */ int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb, int index) { … } EXPORT_SYMBOL_GPL(…); #endif /* CONFIG_OF */ #endif /* CONFIG_VIDEOMODE_HELPERS */ #else int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) { return 1; } void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { } void fb_destroy_modedb(struct fb_videomode *modedb) { } int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) { return -EINVAL; } #endif /* CONFIG_FB_MODE_HELPERS */ /* * fb_validate_mode - validates var against monitor capabilities * @var: pointer to fb_var_screeninfo * @info: pointer to fb_info * * DESCRIPTION: * Validates video mode against monitor capabilities specified in * info->monspecs. * * REQUIRES: * A valid info->monspecs. */ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) { … } #if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86) /* * We need to ensure that the EDID block is only returned for * the primary graphics adapter. */ const unsigned char *fb_firmware_edid(struct device *device) { … } #else const unsigned char *fb_firmware_edid(struct device *device) { return NULL; } #endif EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); EXPORT_SYMBOL(…);