diff options
author | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2012-01-12 07:52:37 -0500 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2012-02-13 02:28:14 -0500 |
commit | 5dc5f61813a9c3ab7dd0a6982ad044834134db5a (patch) | |
tree | 4a50b6713eed9d2d01d1e4cdbc8ecd1a4393e035 /drivers/video/via | |
parent | 2c4c8a8a73b64a8ea86ad85d8a59a5914d2f81ea (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.c | 20 | ||||
-rw-r--r-- | drivers/video/via/via_aux.h | 6 | ||||
-rw-r--r-- | drivers/video/via/via_aux_edid.c | 59 | ||||
-rw-r--r-- | drivers/video/via/viafbdev.c | 26 |
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 | |||
74 | const 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 | ||
32 | struct via_aux_bus { | 33 | struct 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 | ||
48 | struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap); | 53 | struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap); |
49 | void via_aux_free(struct via_aux_bus *bus); | 54 | void via_aux_free(struct via_aux_bus *bus); |
55 | const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus); | ||
50 | 56 | ||
51 | 57 | ||
52 | static inline bool via_aux_add(struct via_aux_drv *drv) | 58 | static 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 | ||
28 | static const char *name = "EDID"; | 30 | static const char *name = "EDID"; |
29 | 31 | ||
30 | 32 | ||
33 | static 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 | |||
59 | static 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 | |||
76 | static 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 | |||
31 | void via_aux_edid_probe(struct via_aux_bus *bus) | 84 | void 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 | ||
1674 | static int parse_mode(const char *str, u32 *xres, u32 *yres) | 1674 | static 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 |