fbmon.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. /*
  2. * linux/drivers/video/fbmon.c
  3. *
  4. * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
  5. *
  6. * Credits:
  7. *
  8. * The EDID Parser is a conglomeration from the following sources:
  9. *
  10. * 1. SciTech SNAP Graphics Architecture
  11. * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
  12. *
  13. * 2. XFree86 4.3.0, interpret_edid.c
  14. * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
  15. *
  16. * 3. John Fremlin <vii@users.sourceforge.net> and
  17. * Ani Joshi <ajoshi@unixbox.com>
  18. *
  19. * Generalized Timing Formula is derived from:
  20. *
  21. * GTF Spreadsheet by Andy Morrish (1/5/97)
  22. * available at http://www.vesa.org
  23. *
  24. * This file is subject to the terms and conditions of the GNU General Public
  25. * License. See the file COPYING in the main directory of this archive
  26. * for more details.
  27. *
  28. */
  29. #include <linux/tty.h>
  30. #include <linux/fb.h>
  31. #include <linux/module.h>
  32. #include <video/edid.h>
  33. #ifdef CONFIG_PPC_OF
  34. #include <linux/pci.h>
  35. #include <asm/prom.h>
  36. #include <asm/pci-bridge.h>
  37. #endif
  38. #include "edid.h"
  39. /*
  40. * EDID parser
  41. */
  42. #undef DEBUG /* define this for verbose EDID parsing output */
  43. #ifdef DEBUG
  44. #define DPRINTK(fmt, args...) printk(fmt,## args)
  45. #else
  46. #define DPRINTK(fmt, args...)
  47. #endif
  48. #define FBMON_FIX_HEADER 1
  49. #define FBMON_FIX_INPUT 2
  50. #ifdef CONFIG_FB_MODE_HELPERS
  51. struct broken_edid {
  52. u8 manufacturer[4];
  53. u32 model;
  54. u32 fix;
  55. };
  56. static struct broken_edid brokendb[] = {
  57. /* DEC FR-PCXAV-YZ */
  58. {
  59. .manufacturer = "DEC",
  60. .model = 0x073a,
  61. .fix = FBMON_FIX_HEADER,
  62. },
  63. /* ViewSonic PF775a */
  64. {
  65. .manufacturer = "VSC",
  66. .model = 0x5a44,
  67. .fix = FBMON_FIX_INPUT,
  68. },
  69. };
  70. static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
  71. 0xff, 0xff, 0xff, 0x00
  72. };
  73. static void copy_string(unsigned char *c, unsigned char *s)
  74. {
  75. int i;
  76. c = c + 5;
  77. for (i = 0; (i < 13 && *c != 0x0A); i++)
  78. *(s++) = *(c++);
  79. *s = 0;
  80. while (i-- && (*--s == 0x20)) *s = 0;
  81. }
  82. static int check_edid(unsigned char *edid)
  83. {
  84. unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
  85. unsigned char *b;
  86. u32 model;
  87. int i, fix = 0, ret = 0;
  88. manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
  89. manufacturer[1] = ((block[0] & 0x03) << 3) +
  90. ((block[1] & 0xe0) >> 5) + '@';
  91. manufacturer[2] = (block[1] & 0x1f) + '@';
  92. manufacturer[3] = 0;
  93. model = block[2] + (block[3] << 8);
  94. for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
  95. if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
  96. brokendb[i].model == model) {
  97. printk("fbmon: The EDID Block of "
  98. "Manufacturer: %s Model: 0x%x is known to "
  99. "be broken,\n", manufacturer, model);
  100. fix = brokendb[i].fix;
  101. break;
  102. }
  103. }
  104. switch (fix) {
  105. case FBMON_FIX_HEADER:
  106. for (i = 0; i < 8; i++) {
  107. if (edid[i] != edid_v1_header[i])
  108. ret = fix;
  109. }
  110. break;
  111. case FBMON_FIX_INPUT:
  112. b = edid + EDID_STRUCT_DISPLAY;
  113. /* Only if display is GTF capable will
  114. the input type be reset to analog */
  115. if (b[4] & 0x01 && b[0] & 0x80)
  116. ret = fix;
  117. break;
  118. }
  119. return ret;
  120. }
  121. static void fix_edid(unsigned char *edid, int fix)
  122. {
  123. unsigned char *b;
  124. switch (fix) {
  125. case FBMON_FIX_HEADER:
  126. printk("fbmon: trying a header reconstruct\n");
  127. memcpy(edid, edid_v1_header, 8);
  128. break;
  129. case FBMON_FIX_INPUT:
  130. printk("fbmon: trying to fix input type\n");
  131. b = edid + EDID_STRUCT_DISPLAY;
  132. b[0] &= ~0x80;
  133. edid[127] += 0x80;
  134. }
  135. }
  136. static int edid_checksum(unsigned char *edid)
  137. {
  138. unsigned char i, csum = 0, all_null = 0;
  139. int err = 0, fix = check_edid(edid);
  140. if (fix)
  141. fix_edid(edid, fix);
  142. for (i = 0; i < EDID_LENGTH; i++) {
  143. csum += edid[i];
  144. all_null |= edid[i];
  145. }
  146. if (csum == 0x00 && all_null) {
  147. /* checksum passed, everything's good */
  148. err = 1;
  149. }
  150. return err;
  151. }
  152. static int edid_check_header(unsigned char *edid)
  153. {
  154. int i, err = 1, fix = check_edid(edid);
  155. if (fix)
  156. fix_edid(edid, fix);
  157. for (i = 0; i < 8; i++) {
  158. if (edid[i] != edid_v1_header[i])
  159. err = 0;
  160. }
  161. return err;
  162. }
  163. static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
  164. {
  165. specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
  166. specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
  167. ((block[1] & 0xe0) >> 5) + '@';
  168. specs->manufacturer[2] = (block[1] & 0x1f) + '@';
  169. specs->manufacturer[3] = 0;
  170. specs->model = block[2] + (block[3] << 8);
  171. specs->serial = block[4] + (block[5] << 8) +
  172. (block[6] << 16) + (block[7] << 24);
  173. specs->year = block[9] + 1990;
  174. specs->week = block[8];
  175. DPRINTK(" Manufacturer: %s\n", specs->manufacturer);
  176. DPRINTK(" Model: %x\n", specs->model);
  177. DPRINTK(" Serial#: %u\n", specs->serial);
  178. DPRINTK(" Year: %u Week %u\n", specs->year, specs->week);
  179. }
  180. static void get_dpms_capabilities(unsigned char flags,
  181. struct fb_monspecs *specs)
  182. {
  183. specs->dpms = 0;
  184. if (flags & DPMS_ACTIVE_OFF)
  185. specs->dpms |= FB_DPMS_ACTIVE_OFF;
  186. if (flags & DPMS_SUSPEND)
  187. specs->dpms |= FB_DPMS_SUSPEND;
  188. if (flags & DPMS_STANDBY)
  189. specs->dpms |= FB_DPMS_STANDBY;
  190. DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n",
  191. (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
  192. (flags & DPMS_SUSPEND) ? "yes" : "no",
  193. (flags & DPMS_STANDBY) ? "yes" : "no");
  194. }
  195. static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
  196. {
  197. int tmp;
  198. DPRINTK(" Chroma\n");
  199. /* Chromaticity data */
  200. tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
  201. tmp *= 1000;
  202. tmp += 512;
  203. specs->chroma.redx = tmp/1024;
  204. DPRINTK(" RedX: 0.%03d ", specs->chroma.redx);
  205. tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
  206. tmp *= 1000;
  207. tmp += 512;
  208. specs->chroma.redy = tmp/1024;
  209. DPRINTK("RedY: 0.%03d\n", specs->chroma.redy);
  210. tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
  211. tmp *= 1000;
  212. tmp += 512;
  213. specs->chroma.greenx = tmp/1024;
  214. DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx);
  215. tmp = (block[5] & 3) | (block[0xa] << 2);
  216. tmp *= 1000;
  217. tmp += 512;
  218. specs->chroma.greeny = tmp/1024;
  219. DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny);
  220. tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
  221. tmp *= 1000;
  222. tmp += 512;
  223. specs->chroma.bluex = tmp/1024;
  224. DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex);
  225. tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
  226. tmp *= 1000;
  227. tmp += 512;
  228. specs->chroma.bluey = tmp/1024;
  229. DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey);
  230. tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
  231. tmp *= 1000;
  232. tmp += 512;
  233. specs->chroma.whitex = tmp/1024;
  234. DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex);
  235. tmp = (block[6] & 3) | (block[0xe] << 2);
  236. tmp *= 1000;
  237. tmp += 512;
  238. specs->chroma.whitey = tmp/1024;
  239. DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey);
  240. }
  241. static int edid_is_serial_block(unsigned char *block)
  242. {
  243. if ((block[0] == 0x00) && (block[1] == 0x00) &&
  244. (block[2] == 0x00) && (block[3] == 0xff) &&
  245. (block[4] == 0x00))
  246. return 1;
  247. else
  248. return 0;
  249. }
  250. static int edid_is_ascii_block(unsigned char *block)
  251. {
  252. if ((block[0] == 0x00) && (block[1] == 0x00) &&
  253. (block[2] == 0x00) && (block[3] == 0xfe) &&
  254. (block[4] == 0x00))
  255. return 1;
  256. else
  257. return 0;
  258. }
  259. static int edid_is_limits_block(unsigned char *block)
  260. {
  261. if ((block[0] == 0x00) && (block[1] == 0x00) &&
  262. (block[2] == 0x00) && (block[3] == 0xfd) &&
  263. (block[4] == 0x00))
  264. return 1;
  265. else
  266. return 0;
  267. }
  268. static int edid_is_monitor_block(unsigned char *block)
  269. {
  270. if ((block[0] == 0x00) && (block[1] == 0x00) &&
  271. (block[2] == 0x00) && (block[3] == 0xfc) &&
  272. (block[4] == 0x00))
  273. return 1;
  274. else
  275. return 0;
  276. }
  277. static void calc_mode_timings(int xres, int yres, int refresh,
  278. struct fb_videomode *mode)
  279. {
  280. struct fb_var_screeninfo var;
  281. struct fb_info info;
  282. memset(&var, 0, sizeof(struct fb_var_screeninfo));
  283. var.xres = xres;
  284. var.yres = yres;
  285. fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
  286. refresh, &var, &info);
  287. mode->xres = xres;
  288. mode->yres = yres;
  289. mode->pixclock = var.pixclock;
  290. mode->refresh = refresh;
  291. mode->left_margin = var.left_margin;
  292. mode->right_margin = var.right_margin;
  293. mode->upper_margin = var.upper_margin;
  294. mode->lower_margin = var.lower_margin;
  295. mode->hsync_len = var.hsync_len;
  296. mode->vsync_len = var.vsync_len;
  297. mode->vmode = 0;
  298. mode->sync = 0;
  299. }
  300. static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
  301. {
  302. int num = 0;
  303. unsigned char c;
  304. c = block[0];
  305. if (c&0x80) {
  306. calc_mode_timings(720, 400, 70, &mode[num]);
  307. mode[num++].flag = FB_MODE_IS_CALCULATED;
  308. DPRINTK(" 720x400@70Hz\n");
  309. }
  310. if (c&0x40) {
  311. calc_mode_timings(720, 400, 88, &mode[num]);
  312. mode[num++].flag = FB_MODE_IS_CALCULATED;
  313. DPRINTK(" 720x400@88Hz\n");
  314. }
  315. if (c&0x20) {
  316. mode[num++] = vesa_modes[3];
  317. DPRINTK(" 640x480@60Hz\n");
  318. }
  319. if (c&0x10) {
  320. calc_mode_timings(640, 480, 67, &mode[num]);
  321. mode[num++].flag = FB_MODE_IS_CALCULATED;
  322. DPRINTK(" 640x480@67Hz\n");
  323. }
  324. if (c&0x08) {
  325. mode[num++] = vesa_modes[4];
  326. DPRINTK(" 640x480@72Hz\n");
  327. }
  328. if (c&0x04) {
  329. mode[num++] = vesa_modes[5];
  330. DPRINTK(" 640x480@75Hz\n");
  331. }
  332. if (c&0x02) {
  333. mode[num++] = vesa_modes[7];
  334. DPRINTK(" 800x600@56Hz\n");
  335. }
  336. if (c&0x01) {
  337. mode[num++] = vesa_modes[8];
  338. DPRINTK(" 800x600@60Hz\n");
  339. }
  340. c = block[1];
  341. if (c&0x80) {
  342. mode[num++] = vesa_modes[9];
  343. DPRINTK(" 800x600@72Hz\n");
  344. }
  345. if (c&0x40) {
  346. mode[num++] = vesa_modes[10];
  347. DPRINTK(" 800x600@75Hz\n");
  348. }
  349. if (c&0x20) {
  350. calc_mode_timings(832, 624, 75, &mode[num]);
  351. mode[num++].flag = FB_MODE_IS_CALCULATED;
  352. DPRINTK(" 832x624@75Hz\n");
  353. }
  354. if (c&0x10) {
  355. mode[num++] = vesa_modes[12];
  356. DPRINTK(" 1024x768@87Hz Interlaced\n");
  357. }
  358. if (c&0x08) {
  359. mode[num++] = vesa_modes[13];
  360. DPRINTK(" 1024x768@60Hz\n");
  361. }
  362. if (c&0x04) {
  363. mode[num++] = vesa_modes[14];
  364. DPRINTK(" 1024x768@70Hz\n");
  365. }
  366. if (c&0x02) {
  367. mode[num++] = vesa_modes[15];
  368. DPRINTK(" 1024x768@75Hz\n");
  369. }
  370. if (c&0x01) {
  371. mode[num++] = vesa_modes[21];
  372. DPRINTK(" 1280x1024@75Hz\n");
  373. }
  374. c = block[2];
  375. if (c&0x80) {
  376. mode[num++] = vesa_modes[17];
  377. DPRINTK(" 1152x870@75Hz\n");
  378. }
  379. DPRINTK(" Manufacturer's mask: %x\n",c&0x7F);
  380. return num;
  381. }
  382. static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
  383. {
  384. int xres, yres = 0, refresh, ratio, i;
  385. xres = (block[0] + 31) * 8;
  386. if (xres <= 256)
  387. return 0;
  388. ratio = (block[1] & 0xc0) >> 6;
  389. switch (ratio) {
  390. case 0:
  391. yres = xres;
  392. break;
  393. case 1:
  394. yres = (xres * 3)/4;
  395. break;
  396. case 2:
  397. yres = (xres * 4)/5;
  398. break;
  399. case 3:
  400. yres = (xres * 9)/16;
  401. break;
  402. }
  403. refresh = (block[1] & 0x3f) + 60;
  404. DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
  405. for (i = 0; i < VESA_MODEDB_SIZE; i++) {
  406. if (vesa_modes[i].xres == xres &&
  407. vesa_modes[i].yres == yres &&
  408. vesa_modes[i].refresh == refresh) {
  409. *mode = vesa_modes[i];
  410. mode->flag |= FB_MODE_IS_STANDARD;
  411. return 1;
  412. }
  413. }
  414. calc_mode_timings(xres, yres, refresh, mode);
  415. return 1;
  416. }
  417. static int get_dst_timing(unsigned char *block,
  418. struct fb_videomode *mode)
  419. {
  420. int j, num = 0;
  421. for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE)
  422. num += get_std_timing(block, &mode[num]);
  423. return num;
  424. }
  425. static void get_detailed_timing(unsigned char *block,
  426. struct fb_videomode *mode)
  427. {
  428. mode->xres = H_ACTIVE;
  429. mode->yres = V_ACTIVE;
  430. mode->pixclock = PIXEL_CLOCK;
  431. mode->pixclock /= 1000;
  432. mode->pixclock = KHZ2PICOS(mode->pixclock);
  433. mode->right_margin = H_SYNC_OFFSET;
  434. mode->left_margin = (H_ACTIVE + H_BLANKING) -
  435. (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
  436. mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
  437. V_SYNC_WIDTH;
  438. mode->lower_margin = V_SYNC_OFFSET;
  439. mode->hsync_len = H_SYNC_WIDTH;
  440. mode->vsync_len = V_SYNC_WIDTH;
  441. if (HSYNC_POSITIVE)
  442. mode->sync |= FB_SYNC_HOR_HIGH_ACT;
  443. if (VSYNC_POSITIVE)
  444. mode->sync |= FB_SYNC_VERT_HIGH_ACT;
  445. mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
  446. (V_ACTIVE + V_BLANKING));
  447. mode->vmode = 0;
  448. mode->flag = FB_MODE_IS_DETAILED;
  449. DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
  450. DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
  451. H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
  452. DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
  453. V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
  454. DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
  455. (VSYNC_POSITIVE) ? "+" : "-");
  456. }
  457. /**
  458. * fb_create_modedb - create video mode database
  459. * @edid: EDID data
  460. * @dbsize: database size
  461. *
  462. * RETURNS: struct fb_videomode, @dbsize contains length of database
  463. *
  464. * DESCRIPTION:
  465. * This function builds a mode database using the contents of the EDID
  466. * data
  467. */
  468. static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
  469. {
  470. struct fb_videomode *mode, *m;
  471. unsigned char *block;
  472. int num = 0, i;
  473. mode = kmalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
  474. if (mode == NULL)
  475. return NULL;
  476. memset(mode, 0, 50 * sizeof(struct fb_videomode));
  477. if (edid == NULL || !edid_checksum(edid) ||
  478. !edid_check_header(edid)) {
  479. kfree(mode);
  480. return NULL;
  481. }
  482. *dbsize = 0;
  483. DPRINTK(" Detailed Timings\n");
  484. block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
  485. for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
  486. int first = 1;
  487. if (!(block[0] == 0x00 && block[1] == 0x00)) {
  488. get_detailed_timing(block, &mode[num]);
  489. if (first) {
  490. mode[num].flag |= FB_MODE_IS_FIRST;
  491. first = 0;
  492. }
  493. num++;
  494. }
  495. }
  496. DPRINTK(" Supported VESA Modes\n");
  497. block = edid + ESTABLISHED_TIMING_1;
  498. num += get_est_timing(block, &mode[num]);
  499. DPRINTK(" Standard Timings\n");
  500. block = edid + STD_TIMING_DESCRIPTIONS_START;
  501. for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
  502. num += get_std_timing(block, &mode[num]);
  503. block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
  504. for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
  505. if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
  506. num += get_dst_timing(block + 5, &mode[num]);
  507. }
  508. /* Yikes, EDID data is totally useless */
  509. if (!num) {
  510. kfree(mode);
  511. return NULL;
  512. }
  513. *dbsize = num;
  514. m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);
  515. if (!m)
  516. return mode;
  517. memmove(m, mode, num * sizeof(struct fb_videomode));
  518. kfree(mode);
  519. return m;
  520. }
  521. /**
  522. * fb_destroy_modedb - destroys mode database
  523. * @modedb: mode database to destroy
  524. *
  525. * DESCRIPTION:
  526. * Destroy mode database created by fb_create_modedb
  527. */
  528. void fb_destroy_modedb(struct fb_videomode *modedb)
  529. {
  530. kfree(modedb);
  531. }
  532. static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
  533. {
  534. int i, retval = 1;
  535. unsigned char *block;
  536. block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
  537. DPRINTK(" Monitor Operating Limits: ");
  538. for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
  539. if (edid_is_limits_block(block)) {
  540. specs->hfmin = H_MIN_RATE * 1000;
  541. specs->hfmax = H_MAX_RATE * 1000;
  542. specs->vfmin = V_MIN_RATE;
  543. specs->vfmax = V_MAX_RATE;
  544. specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
  545. specs->gtf = (GTF_SUPPORT) ? 1 : 0;
  546. retval = 0;
  547. DPRINTK("From EDID\n");
  548. break;
  549. }
  550. }
  551. /* estimate monitor limits based on modes supported */
  552. if (retval) {
  553. struct fb_videomode *modes;
  554. int num_modes, i, hz, hscan, pixclock;
  555. modes = fb_create_modedb(edid, &num_modes);
  556. if (!modes) {
  557. DPRINTK("None Available\n");
  558. return 1;
  559. }
  560. retval = 0;
  561. for (i = 0; i < num_modes; i++) {
  562. hz = modes[i].refresh;
  563. pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
  564. hscan = (modes[i].yres * 105 * hz + 5000)/100;
  565. if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
  566. specs->dclkmax = pixclock;
  567. if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
  568. specs->dclkmin = pixclock;
  569. if (specs->hfmax == 0 || specs->hfmax < hscan)
  570. specs->hfmax = hscan;
  571. if (specs->hfmin == 0 || specs->hfmin > hscan)
  572. specs->hfmin = hscan;
  573. if (specs->vfmax == 0 || specs->vfmax < hz)
  574. specs->vfmax = hz;
  575. if (specs->vfmin == 0 || specs->vfmin > hz)
  576. specs->vfmin = hz;
  577. }
  578. DPRINTK("Extrapolated\n");
  579. fb_destroy_modedb(modes);
  580. }
  581. DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
  582. specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
  583. specs->vfmax, specs->dclkmax/1000000);
  584. return retval;
  585. }
  586. static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
  587. {
  588. unsigned char c, *block;
  589. block = edid + EDID_STRUCT_DISPLAY;
  590. fb_get_monitor_limits(edid, specs);
  591. c = block[0] & 0x80;
  592. specs->input = 0;
  593. if (c) {
  594. specs->input |= FB_DISP_DDI;
  595. DPRINTK(" Digital Display Input");
  596. } else {
  597. DPRINTK(" Analog Display Input: Input Voltage - ");
  598. switch ((block[0] & 0x60) >> 5) {
  599. case 0:
  600. DPRINTK("0.700V/0.300V");
  601. specs->input |= FB_DISP_ANA_700_300;
  602. break;
  603. case 1:
  604. DPRINTK("0.714V/0.286V");
  605. specs->input |= FB_DISP_ANA_714_286;
  606. break;
  607. case 2:
  608. DPRINTK("1.000V/0.400V");
  609. specs->input |= FB_DISP_ANA_1000_400;
  610. break;
  611. case 3:
  612. DPRINTK("0.700V/0.000V");
  613. specs->input |= FB_DISP_ANA_700_000;
  614. break;
  615. }
  616. }
  617. DPRINTK("\n Sync: ");
  618. c = block[0] & 0x10;
  619. if (c)
  620. DPRINTK(" Configurable signal level\n");
  621. c = block[0] & 0x0f;
  622. specs->signal = 0;
  623. if (c & 0x10) {
  624. DPRINTK("Blank to Blank ");
  625. specs->signal |= FB_SIGNAL_BLANK_BLANK;
  626. }
  627. if (c & 0x08) {
  628. DPRINTK("Separate ");
  629. specs->signal |= FB_SIGNAL_SEPARATE;
  630. }
  631. if (c & 0x04) {
  632. DPRINTK("Composite ");
  633. specs->signal |= FB_SIGNAL_COMPOSITE;
  634. }
  635. if (c & 0x02) {
  636. DPRINTK("Sync on Green ");
  637. specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
  638. }
  639. if (c & 0x01) {
  640. DPRINTK("Serration on ");
  641. specs->signal |= FB_SIGNAL_SERRATION_ON;
  642. }
  643. DPRINTK("\n");
  644. specs->max_x = block[1];
  645. specs->max_y = block[2];
  646. DPRINTK(" Max H-size in cm: ");
  647. if (specs->max_x)
  648. DPRINTK("%d\n", specs->max_x);
  649. else
  650. DPRINTK("variable\n");
  651. DPRINTK(" Max V-size in cm: ");
  652. if (specs->max_y)
  653. DPRINTK("%d\n", specs->max_y);
  654. else
  655. DPRINTK("variable\n");
  656. c = block[3];
  657. specs->gamma = c+100;
  658. DPRINTK(" Gamma: ");
  659. DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
  660. get_dpms_capabilities(block[4], specs);
  661. switch ((block[4] & 0x18) >> 3) {
  662. case 0:
  663. DPRINTK(" Monochrome/Grayscale\n");
  664. specs->input |= FB_DISP_MONO;
  665. break;
  666. case 1:
  667. DPRINTK(" RGB Color Display\n");
  668. specs->input |= FB_DISP_RGB;
  669. break;
  670. case 2:
  671. DPRINTK(" Non-RGB Multicolor Display\n");
  672. specs->input |= FB_DISP_MULTI;
  673. break;
  674. default:
  675. DPRINTK(" Unknown\n");
  676. specs->input |= FB_DISP_UNKNOWN;
  677. break;
  678. }
  679. get_chroma(block, specs);
  680. specs->misc = 0;
  681. c = block[4] & 0x7;
  682. if (c & 0x04) {
  683. DPRINTK(" Default color format is primary\n");
  684. specs->misc |= FB_MISC_PRIM_COLOR;
  685. }
  686. if (c & 0x02) {
  687. DPRINTK(" First DETAILED Timing is preferred\n");
  688. specs->misc |= FB_MISC_1ST_DETAIL;
  689. }
  690. if (c & 0x01) {
  691. printk(" Display is GTF capable\n");
  692. specs->gtf = 1;
  693. }
  694. }
  695. static int edid_is_timing_block(unsigned char *block)
  696. {
  697. if ((block[0] != 0x00) || (block[1] != 0x00) ||
  698. (block[2] != 0x00) || (block[4] != 0x00))
  699. return 1;
  700. else
  701. return 0;
  702. }
  703. int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
  704. {
  705. int i;
  706. unsigned char *block;
  707. if (edid == NULL || var == NULL)
  708. return 1;
  709. if (!(edid_checksum(edid)))
  710. return 1;
  711. if (!(edid_check_header(edid)))
  712. return 1;
  713. block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
  714. for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
  715. if (edid_is_timing_block(block)) {
  716. var->xres = var->xres_virtual = H_ACTIVE;
  717. var->yres = var->yres_virtual = V_ACTIVE;
  718. var->height = var->width = -1;
  719. var->right_margin = H_SYNC_OFFSET;
  720. var->left_margin = (H_ACTIVE + H_BLANKING) -
  721. (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
  722. var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
  723. V_SYNC_WIDTH;
  724. var->lower_margin = V_SYNC_OFFSET;
  725. var->hsync_len = H_SYNC_WIDTH;
  726. var->vsync_len = V_SYNC_WIDTH;
  727. var->pixclock = PIXEL_CLOCK;
  728. var->pixclock /= 1000;
  729. var->pixclock = KHZ2PICOS(var->pixclock);
  730. if (HSYNC_POSITIVE)
  731. var->sync |= FB_SYNC_HOR_HIGH_ACT;
  732. if (VSYNC_POSITIVE)
  733. var->sync |= FB_SYNC_VERT_HIGH_ACT;
  734. return 0;
  735. }
  736. }
  737. return 1;
  738. }
  739. void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
  740. {
  741. unsigned char *block;
  742. int i, found = 0;
  743. if (edid == NULL)
  744. return;
  745. if (!(edid_checksum(edid)))
  746. return;
  747. if (!(edid_check_header(edid)))
  748. return;
  749. memset(specs, 0, sizeof(struct fb_monspecs));
  750. specs->version = edid[EDID_STRUCT_VERSION];
  751. specs->revision = edid[EDID_STRUCT_REVISION];
  752. DPRINTK("========================================\n");
  753. DPRINTK("Display Information (EDID)\n");
  754. DPRINTK("========================================\n");
  755. DPRINTK(" EDID Version %d.%d\n", (int) specs->version,
  756. (int) specs->revision);
  757. parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
  758. block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
  759. for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
  760. if (edid_is_serial_block(block)) {
  761. copy_string(block, specs->serial_no);
  762. DPRINTK(" Serial Number: %s\n", specs->serial_no);
  763. } else if (edid_is_ascii_block(block)) {
  764. copy_string(block, specs->ascii);
  765. DPRINTK(" ASCII Block: %s\n", specs->ascii);
  766. } else if (edid_is_monitor_block(block)) {
  767. copy_string(block, specs->monitor);
  768. DPRINTK(" Monitor Name: %s\n", specs->monitor);
  769. }
  770. }
  771. DPRINTK(" Display Characteristics:\n");
  772. get_monspecs(edid, specs);
  773. specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
  774. /*
  775. * Workaround for buggy EDIDs that sets that the first
  776. * detailed timing is preferred but has not detailed
  777. * timing specified
  778. */
  779. for (i = 0; i < specs->modedb_len; i++) {
  780. if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
  781. found = 1;
  782. break;
  783. }
  784. }
  785. if (!found)
  786. specs->misc &= ~FB_MISC_1ST_DETAIL;
  787. DPRINTK("========================================\n");
  788. }
  789. /*
  790. * VESA Generalized Timing Formula (GTF)
  791. */
  792. #define FLYBACK 550
  793. #define V_FRONTPORCH 1
  794. #define H_OFFSET 40
  795. #define H_SCALEFACTOR 20
  796. #define H_BLANKSCALE 128
  797. #define H_GRADIENT 600
  798. #define C_VAL 30
  799. #define M_VAL 300
  800. struct __fb_timings {
  801. u32 dclk;
  802. u32 hfreq;
  803. u32 vfreq;
  804. u32 hactive;
  805. u32 vactive;
  806. u32 hblank;
  807. u32 vblank;
  808. u32 htotal;
  809. u32 vtotal;
  810. };
  811. /**
  812. * fb_get_vblank - get vertical blank time
  813. * @hfreq: horizontal freq
  814. *
  815. * DESCRIPTION:
  816. * vblank = right_margin + vsync_len + left_margin
  817. *
  818. * given: right_margin = 1 (V_FRONTPORCH)
  819. * vsync_len = 3
  820. * flyback = 550
  821. *
  822. * flyback * hfreq
  823. * left_margin = --------------- - vsync_len
  824. * 1000000
  825. */
  826. static u32 fb_get_vblank(u32 hfreq)
  827. {
  828. u32 vblank;
  829. vblank = (hfreq * FLYBACK)/1000;
  830. vblank = (vblank + 500)/1000;
  831. return (vblank + V_FRONTPORCH);
  832. }
  833. /**
  834. * fb_get_hblank_by_freq - get horizontal blank time given hfreq
  835. * @hfreq: horizontal freq
  836. * @xres: horizontal resolution in pixels
  837. *
  838. * DESCRIPTION:
  839. *
  840. * xres * duty_cycle
  841. * hblank = ------------------
  842. * 100 - duty_cycle
  843. *
  844. * duty cycle = percent of htotal assigned to inactive display
  845. * duty cycle = C - (M/Hfreq)
  846. *
  847. * where: C = ((offset - scale factor) * blank_scale)
  848. * -------------------------------------- + scale factor
  849. * 256
  850. * M = blank_scale * gradient
  851. *
  852. */
  853. static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
  854. {
  855. u32 c_val, m_val, duty_cycle, hblank;
  856. c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
  857. H_SCALEFACTOR) * 1000;
  858. m_val = (H_BLANKSCALE * H_GRADIENT)/256;
  859. m_val = (m_val * 1000000)/hfreq;
  860. duty_cycle = c_val - m_val;
  861. hblank = (xres * duty_cycle)/(100000 - duty_cycle);
  862. return (hblank);
  863. }
  864. /**
  865. * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
  866. * @dclk: pixelclock in Hz
  867. * @xres: horizontal resolution in pixels
  868. *
  869. * DESCRIPTION:
  870. *
  871. * xres * duty_cycle
  872. * hblank = ------------------
  873. * 100 - duty_cycle
  874. *
  875. * duty cycle = percent of htotal assigned to inactive display
  876. * duty cycle = C - (M * h_period)
  877. *
  878. * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
  879. * -----------------------------------------------
  880. * 2 * M
  881. * M = 300;
  882. * C = 30;
  883. */
  884. static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
  885. {
  886. u32 duty_cycle, h_period, hblank;
  887. dclk /= 1000;
  888. h_period = 100 - C_VAL;
  889. h_period *= h_period;
  890. h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
  891. h_period *=10000;
  892. h_period = int_sqrt(h_period);
  893. h_period -= (100 - C_VAL) * 100;
  894. h_period *= 1000;
  895. h_period /= 2 * M_VAL;
  896. duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
  897. hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
  898. hblank &= ~15;
  899. return (hblank);
  900. }
  901. /**
  902. * fb_get_hfreq - estimate hsync
  903. * @vfreq: vertical refresh rate
  904. * @yres: vertical resolution
  905. *
  906. * DESCRIPTION:
  907. *
  908. * (yres + front_port) * vfreq * 1000000
  909. * hfreq = -------------------------------------
  910. * (1000000 - (vfreq * FLYBACK)
  911. *
  912. */
  913. static u32 fb_get_hfreq(u32 vfreq, u32 yres)
  914. {
  915. u32 divisor, hfreq;
  916. divisor = (1000000 - (vfreq * FLYBACK))/1000;
  917. hfreq = (yres + V_FRONTPORCH) * vfreq * 1000;
  918. return (hfreq/divisor);
  919. }
  920. static void fb_timings_vfreq(struct __fb_timings *timings)
  921. {
  922. timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
  923. timings->vblank = fb_get_vblank(timings->hfreq);
  924. timings->vtotal = timings->vactive + timings->vblank;
  925. timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
  926. timings->hactive);
  927. timings->htotal = timings->hactive + timings->hblank;
  928. timings->dclk = timings->htotal * timings->hfreq;
  929. }
  930. static void fb_timings_hfreq(struct __fb_timings *timings)
  931. {
  932. timings->vblank = fb_get_vblank(timings->hfreq);
  933. timings->vtotal = timings->vactive + timings->vblank;
  934. timings->vfreq = timings->hfreq/timings->vtotal;
  935. timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
  936. timings->hactive);
  937. timings->htotal = timings->hactive + timings->hblank;
  938. timings->dclk = timings->htotal * timings->hfreq;
  939. }
  940. static void fb_timings_dclk(struct __fb_timings *timings)
  941. {
  942. timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
  943. timings->hactive);
  944. timings->htotal = timings->hactive + timings->hblank;
  945. timings->hfreq = timings->dclk/timings->htotal;
  946. timings->vblank = fb_get_vblank(timings->hfreq);
  947. timings->vtotal = timings->vactive + timings->vblank;
  948. timings->vfreq = timings->hfreq/timings->vtotal;
  949. }
  950. /*
  951. * fb_get_mode - calculates video mode using VESA GTF
  952. * @flags: if: 0 - maximize vertical refresh rate
  953. * 1 - vrefresh-driven calculation;
  954. * 2 - hscan-driven calculation;
  955. * 3 - pixelclock-driven calculation;
  956. * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock
  957. * @var: pointer to fb_var_screeninfo
  958. * @info: pointer to fb_info
  959. *
  960. * DESCRIPTION:
  961. * Calculates video mode based on monitor specs using VESA GTF.
  962. * The GTF is best for VESA GTF compliant monitors but is
  963. * specifically formulated to work for older monitors as well.
  964. *
  965. * If @flag==0, the function will attempt to maximize the
  966. * refresh rate. Otherwise, it will calculate timings based on
  967. * the flag and accompanying value.
  968. *
  969. * If FB_IGNOREMON bit is set in @flags, monitor specs will be
  970. * ignored and @var will be filled with the calculated timings.
  971. *
  972. * All calculations are based on the VESA GTF Spreadsheet
  973. * available at VESA's public ftp (http://www.vesa.org).
  974. *
  975. * NOTES:
  976. * The timings generated by the GTF will be different from VESA
  977. * DMT. It might be a good idea to keep a table of standard
  978. * VESA modes as well. The GTF may also not work for some displays,
  979. * such as, and especially, analog TV.
  980. *
  981. * REQUIRES:
  982. * A valid info->monspecs, otherwise 'safe numbers' will be used.
  983. */
  984. int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
  985. {
  986. struct __fb_timings timings;
  987. u32 interlace = 1, dscan = 1;
  988. u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
  989. /*
  990. * If monspecs are invalid, use values that are enough
  991. * for 640x480@60
  992. */
  993. if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
  994. !info->monspecs.dclkmax ||
  995. info->monspecs.hfmax < info->monspecs.hfmin ||
  996. info->monspecs.vfmax < info->monspecs.vfmin ||
  997. info->monspecs.dclkmax < info->monspecs.dclkmin) {
  998. hfmin = 29000; hfmax = 30000;
  999. vfmin = 60; vfmax = 60;
  1000. dclkmin = 0; dclkmax = 25000000;
  1001. } else {
  1002. hfmin = info->monspecs.hfmin;
  1003. hfmax = info->monspecs.hfmax;
  1004. vfmin = info->monspecs.vfmin;
  1005. vfmax = info->monspecs.vfmax;
  1006. dclkmin = info->monspecs.dclkmin;
  1007. dclkmax = info->monspecs.dclkmax;
  1008. }
  1009. memset(&timings, 0, sizeof(struct __fb_timings));
  1010. timings.hactive = var->xres;
  1011. timings.vactive = var->yres;
  1012. if (var->vmode & FB_VMODE_INTERLACED) {
  1013. timings.vactive /= 2;
  1014. interlace = 2;
  1015. }
  1016. if (var->vmode & FB_VMODE_DOUBLE) {
  1017. timings.vactive *= 2;
  1018. dscan = 2;
  1019. }
  1020. switch (flags & ~FB_IGNOREMON) {
  1021. case FB_MAXTIMINGS: /* maximize refresh rate */
  1022. timings.hfreq = hfmax;
  1023. fb_timings_hfreq(&timings);
  1024. if (timings.vfreq > vfmax) {
  1025. timings.vfreq = vfmax;
  1026. fb_timings_vfreq(&timings);
  1027. }
  1028. if (timings.dclk > dclkmax) {
  1029. timings.dclk = dclkmax;
  1030. fb_timings_dclk(&timings);
  1031. }
  1032. break;
  1033. case FB_VSYNCTIMINGS: /* vrefresh driven */
  1034. timings.vfreq = val;
  1035. fb_timings_vfreq(&timings);
  1036. break;
  1037. case FB_HSYNCTIMINGS: /* hsync driven */
  1038. timings.hfreq = val;
  1039. fb_timings_hfreq(&timings);
  1040. break;
  1041. case FB_DCLKTIMINGS: /* pixelclock driven */
  1042. timings.dclk = PICOS2KHZ(val) * 1000;
  1043. fb_timings_dclk(&timings);
  1044. break;
  1045. default:
  1046. return -EINVAL;
  1047. }
  1048. if (!(flags & FB_IGNOREMON) &&
  1049. (timings.vfreq < vfmin || timings.vfreq > vfmax ||
  1050. timings.hfreq < hfmin || timings.hfreq > hfmax ||
  1051. timings.dclk < dclkmin || timings.dclk > dclkmax))
  1052. return -EINVAL;
  1053. var->pixclock = KHZ2PICOS(timings.dclk/1000);
  1054. var->hsync_len = (timings.htotal * 8)/100;
  1055. var->right_margin = (timings.hblank/2) - var->hsync_len;
  1056. var->left_margin = timings.hblank - var->right_margin - var->hsync_len;
  1057. var->vsync_len = (3 * interlace)/dscan;
  1058. var->lower_margin = (1 * interlace)/dscan;
  1059. var->upper_margin = (timings.vblank * interlace)/dscan -
  1060. (var->vsync_len + var->lower_margin);
  1061. return 0;
  1062. }
  1063. #else
  1064. int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
  1065. {
  1066. return 1;
  1067. }
  1068. void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
  1069. {
  1070. specs = NULL;
  1071. }
  1072. void fb_destroy_modedb(struct fb_videomode *modedb)
  1073. {
  1074. }
  1075. int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
  1076. struct fb_info *info)
  1077. {
  1078. return -EINVAL;
  1079. }
  1080. #endif /* CONFIG_FB_MODE_HELPERS */
  1081. /*
  1082. * fb_validate_mode - validates var against monitor capabilities
  1083. * @var: pointer to fb_var_screeninfo
  1084. * @info: pointer to fb_info
  1085. *
  1086. * DESCRIPTION:
  1087. * Validates video mode against monitor capabilities specified in
  1088. * info->monspecs.
  1089. *
  1090. * REQUIRES:
  1091. * A valid info->monspecs.
  1092. */
  1093. int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
  1094. {
  1095. u32 hfreq, vfreq, htotal, vtotal, pixclock;
  1096. u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
  1097. /*
  1098. * If monspecs are invalid, use values that are enough
  1099. * for 640x480@60
  1100. */
  1101. if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
  1102. !info->monspecs.dclkmax ||
  1103. info->monspecs.hfmax < info->monspecs.hfmin ||
  1104. info->monspecs.vfmax < info->monspecs.vfmin ||
  1105. info->monspecs.dclkmax < info->monspecs.dclkmin) {
  1106. hfmin = 29000; hfmax = 30000;
  1107. vfmin = 60; vfmax = 60;
  1108. dclkmin = 0; dclkmax = 25000000;
  1109. } else {
  1110. hfmin = info->monspecs.hfmin;
  1111. hfmax = info->monspecs.hfmax;
  1112. vfmin = info->monspecs.vfmin;
  1113. vfmax = info->monspecs.vfmax;
  1114. dclkmin = info->monspecs.dclkmin;
  1115. dclkmax = info->monspecs.dclkmax;
  1116. }
  1117. if (!var->pixclock)
  1118. return -EINVAL;
  1119. pixclock = PICOS2KHZ(var->pixclock) * 1000;
  1120. htotal = var->xres + var->right_margin + var->hsync_len +
  1121. var->left_margin;
  1122. vtotal = var->yres + var->lower_margin + var->vsync_len +
  1123. var->upper_margin;
  1124. if (var->vmode & FB_VMODE_INTERLACED)
  1125. vtotal /= 2;
  1126. if (var->vmode & FB_VMODE_DOUBLE)
  1127. vtotal *= 2;
  1128. hfreq = pixclock/htotal;
  1129. hfreq = (hfreq + 500) / 1000 * 1000;
  1130. vfreq = hfreq/vtotal;
  1131. return (vfreq < vfmin || vfreq > vfmax ||
  1132. hfreq < hfmin || hfreq > hfmax ||
  1133. pixclock < dclkmin || pixclock > dclkmax) ?
  1134. -EINVAL : 0;
  1135. }
  1136. #if defined(__i386__)
  1137. #include <linux/pci.h>
  1138. /*
  1139. * We need to ensure that the EDID block is only returned for
  1140. * the primary graphics adapter.
  1141. */
  1142. const unsigned char *fb_firmware_edid(struct device *device)
  1143. {
  1144. struct pci_dev *dev = NULL;
  1145. struct resource *res = NULL;
  1146. unsigned char *edid = NULL;
  1147. if (device)
  1148. dev = to_pci_dev(device);
  1149. if (dev)
  1150. res = &dev->resource[PCI_ROM_RESOURCE];
  1151. if (res && res->flags & IORESOURCE_ROM_SHADOW)
  1152. edid = edid_info.dummy;
  1153. return edid;
  1154. }
  1155. #else
  1156. const unsigned char *fb_firmware_edid(struct device *device)
  1157. {
  1158. return NULL;
  1159. }
  1160. #endif /* _i386_ */
  1161. EXPORT_SYMBOL(fb_parse_edid);
  1162. EXPORT_SYMBOL(fb_edid_to_monspecs);
  1163. EXPORT_SYMBOL(fb_firmware_edid);
  1164. EXPORT_SYMBOL(fb_get_mode);
  1165. EXPORT_SYMBOL(fb_validate_mode);
  1166. EXPORT_SYMBOL(fb_destroy_modedb);