aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/via
diff options
context:
space:
mode:
authorFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2012-01-12 07:52:37 -0500
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2012-02-13 02:28:14 -0500
commit5dc5f61813a9c3ab7dd0a6982ad044834134db5a (patch)
tree4a50b6713eed9d2d01d1e4cdbc8ecd1a4393e035 /drivers/video/via
parent2c4c8a8a73b64a8ea86ad85d8a59a5914d2f81ea (diff)
viafb: add initial EDID support
This patch adds support for using EDID data on CRT and DVP1 for initial configuration if viafb_mode or viafb_mode1 are not present. Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video/via')
-rw-r--r--drivers/video/via/via_aux.c20
-rw-r--r--drivers/video/via/via_aux.h6
-rw-r--r--drivers/video/via/via_aux_edid.c59
-rw-r--r--drivers/video/via/viafbdev.c26
4 files changed, 103 insertions, 8 deletions
diff --git a/drivers/video/via/via_aux.c b/drivers/video/via/via_aux.c
index e728b9bec235..4a0a55cdac3d 100644
--- a/drivers/video/via/via_aux.c
+++ b/drivers/video/via/via_aux.c
@@ -60,9 +60,29 @@ void via_aux_free(struct via_aux_bus *bus)
60 return; 60 return;
61 61
62 list_for_each_entry_safe(pos, n, &bus->drivers, chain) { 62 list_for_each_entry_safe(pos, n, &bus->drivers, chain) {
63 if (pos->cleanup)
64 pos->cleanup(pos);
65
63 list_del(&pos->chain); 66 list_del(&pos->chain);
67 kfree(pos->data);
64 kfree(pos); 68 kfree(pos);
65 } 69 }
66 70
67 kfree(bus); 71 kfree(bus);
68} 72}
73
74const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus)
75{
76 struct via_aux_drv *pos;
77 const struct fb_videomode *mode = NULL;
78
79 if (!bus)
80 return NULL;
81
82 list_for_each_entry(pos, &bus->drivers, chain) {
83 if (pos->get_preferred_mode)
84 mode = pos->get_preferred_mode(pos);
85 }
86
87 return mode;
88}
diff --git a/drivers/video/via/via_aux.h b/drivers/video/via/via_aux.h
index 5a4867a2dcc3..a8de3f038cea 100644
--- a/drivers/video/via/via_aux.h
+++ b/drivers/video/via/via_aux.h
@@ -27,6 +27,7 @@
27 27
28#include <linux/list.h> 28#include <linux/list.h>
29#include <linux/i2c.h> 29#include <linux/i2c.h>
30#include <linux/fb.h>
30 31
31 32
32struct via_aux_bus { 33struct via_aux_bus {
@@ -42,11 +43,16 @@ struct via_aux_drv {
42 43
43 const char *name; /* human readable name of the driver */ 44 const char *name; /* human readable name of the driver */
44 void *data; /* private data of this driver */ 45 void *data; /* private data of this driver */
46
47 void (*cleanup)(struct via_aux_drv *drv);
48 const struct fb_videomode* (*get_preferred_mode)
49 (struct via_aux_drv *drv);
45}; 50};
46 51
47 52
48struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap); 53struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap);
49void via_aux_free(struct via_aux_bus *bus); 54void via_aux_free(struct via_aux_bus *bus);
55const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus);
50 56
51 57
52static inline bool via_aux_add(struct via_aux_drv *drv) 58static inline bool via_aux_add(struct via_aux_drv *drv)
diff --git a/drivers/video/via/via_aux_edid.c b/drivers/video/via/via_aux_edid.c
index 547bff53a448..03f7a41c8a3f 100644
--- a/drivers/video/via/via_aux_edid.c
+++ b/drivers/video/via/via_aux_edid.c
@@ -22,18 +22,75 @@
22 */ 22 */
23 23
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/fb.h>
25#include "via_aux.h" 26#include "via_aux.h"
27#include "../edid.h"
26 28
27 29
28static const char *name = "EDID"; 30static const char *name = "EDID";
29 31
30 32
33static void query_edid(struct via_aux_drv *drv)
34{
35 struct fb_monspecs *spec = drv->data;
36 unsigned char edid[EDID_LENGTH];
37 bool valid = false;
38
39 if (spec)
40 fb_destroy_modedb(spec->modedb);
41 else
42 spec = kmalloc(sizeof(*spec), GFP_KERNEL);
43
44 spec->version = spec->revision = 0;
45 if (via_aux_read(drv, 0x00, edid, EDID_LENGTH)) {
46 fb_edid_to_monspecs(edid, spec);
47 valid = spec->version || spec->revision;
48 }
49
50 if (!valid) {
51 kfree(spec);
52 spec = NULL;
53 } else
54 printk(KERN_DEBUG "EDID: %s %s\n", spec->manufacturer, spec->monitor);
55
56 drv->data = spec;
57}
58
59static const struct fb_videomode *get_preferred_mode(struct via_aux_drv *drv)
60{
61 struct fb_monspecs *spec = drv->data;
62 int i;
63
64 if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL))
65 return NULL;
66
67 for (i = 0; i < spec->modedb_len; i++) {
68 if (spec->modedb[i].flag & FB_MODE_IS_FIRST &&
69 spec->modedb[i].flag & FB_MODE_IS_DETAILED)
70 return &spec->modedb[i];
71 }
72
73 return NULL;
74}
75
76static void cleanup(struct via_aux_drv *drv)
77{
78 struct fb_monspecs *spec = drv->data;
79
80 if (spec)
81 fb_destroy_modedb(spec->modedb);
82}
83
31void via_aux_edid_probe(struct via_aux_bus *bus) 84void via_aux_edid_probe(struct via_aux_bus *bus)
32{ 85{
33 struct via_aux_drv drv = { 86 struct via_aux_drv drv = {
34 .bus = bus, 87 .bus = bus,
35 .addr = 0x50, 88 .addr = 0x50,
36 .name = name}; 89 .name = name,
90 .cleanup = cleanup,
91 .get_preferred_mode = get_preferred_mode};
92
93 query_edid(&drv);
37 94
38 /* as EDID devices can be connected/disconnected just add the driver */ 95 /* as EDID devices can be connected/disconnected just add the driver */
39 via_aux_add(&drv); 96 via_aux_add(&drv);
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 6d5b64923236..47911658f684 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1671,12 +1671,23 @@ static void viafb_remove_proc(struct viafb_shared *shared)
1671} 1671}
1672#undef IS_VT1636 1672#undef IS_VT1636
1673 1673
1674static int parse_mode(const char *str, u32 *xres, u32 *yres) 1674static int parse_mode(const char *str, u32 devices, u32 *xres, u32 *yres)
1675{ 1675{
1676 const struct fb_videomode *mode = NULL;
1676 char *ptr; 1677 char *ptr;
1677 1678
1678 if (!str) { 1679 if (!str) {
1679 if (machine_is_olpc()) { 1680 if (devices == VIA_CRT)
1681 mode = via_aux_get_preferred_mode(
1682 viaparinfo->shared->i2c_26);
1683 else if (devices == VIA_DVP1)
1684 mode = via_aux_get_preferred_mode(
1685 viaparinfo->shared->i2c_31);
1686
1687 if (mode) {
1688 *xres = mode->xres;
1689 *yres = mode->yres;
1690 } else if (machine_is_olpc()) {
1680 *xres = 1200; 1691 *xres = 1200;
1681 *yres = 900; 1692 *yres = 900;
1682 } else { 1693 } else {
@@ -1829,10 +1840,11 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
1829 viafb_second_size * 1024 * 1024; 1840 viafb_second_size * 1024 * 1024;
1830 } 1841 }
1831 1842
1832 parse_mode(viafb_mode, &default_xres, &default_yres); 1843 parse_mode(viafb_mode, viaparinfo->shared->iga1_devices,
1844 &default_xres, &default_yres);
1833 if (viafb_SAMM_ON == 1) 1845 if (viafb_SAMM_ON == 1)
1834 parse_mode(viafb_mode1, &viafb_second_xres, 1846 parse_mode(viafb_mode1, viaparinfo->shared->iga2_devices,
1835 &viafb_second_yres); 1847 &viafb_second_xres, &viafb_second_yres);
1836 1848
1837 default_var.xres = default_xres; 1849 default_var.xres = default_xres;
1838 default_var.yres = default_yres; 1850 default_var.yres = default_yres;
@@ -2060,9 +2072,9 @@ int __init viafb_init(void)
2060 if (r < 0) 2072 if (r < 0)
2061 return r; 2073 return r;
2062#endif 2074#endif
2063 if (parse_mode(viafb_mode, &dummy_x, &dummy_y) 2075 if (parse_mode(viafb_mode, 0, &dummy_x, &dummy_y)
2064 || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh) 2076 || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh)
2065 || parse_mode(viafb_mode1, &dummy_x, &dummy_y) 2077 || parse_mode(viafb_mode1, 0, &dummy_x, &dummy_y)
2066 || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1) 2078 || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1)
2067 || viafb_bpp < 0 || viafb_bpp > 32 2079 || viafb_bpp < 0 || viafb_bpp > 32
2068 || viafb_bpp1 < 0 || viafb_bpp1 > 32 2080 || viafb_bpp1 < 0 || viafb_bpp1 > 32