Finish bringing in LVDS code, re-add to Makefile. Needed other changes too:
authorJesse Barnes <jbarnes@hobbes.virtuousgeek.org>
Tue, 10 Apr 2007 16:47:37 +0000 (09:47 -0700)
committerJesse Barnes <jbarnes@hobbes.virtuousgeek.org>
Tue, 10 Apr 2007 16:47:37 +0000 (09:47 -0700)
  - move EDID structures to drm_edid.h
  - add EDID info structure to drm_output
  - add a few routines to intel_display for getting current mode info
  - add some prototypes to intel_drv.h and drm_crtc.h

linux-core/Makefile.kernel
linux-core/drm_crtc.h
linux-core/drm_edid.c
linux-core/drm_edid.h [new file with mode: 0644]
linux-core/intel_display.c
linux-core/intel_drv.h
linux-core/intel_lvds.c

index 1b767b6..ac403f6 100644 (file)
@@ -20,7 +20,7 @@ r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
 i810-objs   := i810_drv.o i810_dma.o
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
-               i915_buffer.o intel_display.o intel_crt.o  \
+               i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \
                intel_sdvo.o intel_modes.o intel_i2c.o
 nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
                nouveau_object.o nouveau_irq.o \
index 21908f0..775d21e 100644 (file)
@@ -369,6 +369,7 @@ struct drm_output {
        /* xf86MonPtr MonInfo; */
        enum subpixel_order subpixel_order;
        int mm_width, mm_height;
+       struct edid *monitor_info;
        char name[DRM_OUTPUT_LEN];
        const struct drm_output_funcs *funcs;
        void *driver_private;
@@ -455,6 +456,10 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode);
 extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
                                  int adjust_flags);
 extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
+extern bool drm_initial_config(struct drm_device *dev, bool cangrow);
+extern void drm_framebuffer_set_object(struct drm_device *dev,
+                                      unsigned long handle);
+extern bool drm_set_desired_modes(struct drm_device *dev);
 
 #endif /* __DRM_CRTC_H__ */
 
index fcd97d6..b79bc2d 100644 (file)
  *
  * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
  * FB layer.
+ *   Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
  */
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
+#include "drm_edid.h"
 
-#define EDID_LENGTH 128
-#define DDC_ADDR 0x50
-
-#ifdef BIG_ENDIAN
-#error "EDID structure is little endian, need big endian versions"
-#endif
-
-struct est_timings {
-       u8 t1;
-       u8 t2;
-       u8 mfg_rsvd;
-} __attribute__((packed));
-
-struct std_timing {
-       u8 hsize; /* need to multiply by 8 then add 248 */
-       u8 vfreq:6; /* need to add 60 */
-       u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
-} __attribute__((packed));
-
-/* If detailed data is pixel timing */
-struct detailed_pixel_timing {
-       u8 hactive_lo;
-       u8 hblank_lo;
-       u8 hblank_hi:4;
-       u8 hactive_hi:4;
-       u8 vactive_lo;
-       u8 vblank_lo;
-       u8 vblank_hi:4;
-       u8 vactive_hi:4;
-       u8 hsync_offset_lo;
-       u8 hsync_pulse_width_lo;
-       u8 vsync_pulse_width_lo:4;
-       u8 vsync_offset_lo:4;
-       u8 hsync_pulse_width_hi:2;
-       u8 hsync_offset_hi:2;
-       u8 vsync_pulse_width_hi:2;
-       u8 vsync_offset_hi:2;
-       u8 width_mm_lo;
-       u8 height_mm_lo;
-       u8 height_mm_hi:4;
-       u8 width_mm_hi:4;
-       u8 hborder;
-       u8 vborder;
-       u8 unknown0:1;
-       u8 vsync_positive:1;
-       u8 hsync_positive:1;
-       u8 separate_sync:2;
-       u8 stereo:1;
-       u8 unknown6:1;
-       u8 interlaced:1;
-} __attribute__((packed));
-
-/* If it's not pixel timing, it'll be one of the below */
-struct detailed_data_string {
-       u8 str[13];
-} __attribute__((packed));
-
-struct detailed_data_monitor_range {
-       u8 min_vfreq;
-       u8 max_vfreq;
-       u8 min_hfreq_khz;
-       u8 max_hfreq_khz;
-       u8 pixel_clock_mhz; /* need to multiply by 10 */
-       u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */
-       u8 hfreq_start_khz; /* need to multiply by 2 */
-       u8 c; /* need to divide by 2 */
-       u16 m; /* FIXME: byte order */
-       u8 k;
-       u8 j; /* need to divide by 2 */
-} __attribute__((packed));
-
-struct detailed_data_wpindex {
-       u8 white_y_lo:2;
-       u8 white_x_lo:2;
-       u8 pad:4;
-       u8 white_x_hi;
-       u8 white_y_hi;
-       u8 gamma; /* need to divide by 100 then add 1 */
-} __attribute__((packed));
-
-struct detailed_data_color_point {
-       u8 windex1;
-       u8 wpindex1[3];
-       u8 windex2;
-       u8 wpindex2[3];
-} __attribute__((packed));
-
-struct detailed_non_pixel {
-       u8 pad1;
-       u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
-                   fb=color point data, fa=standard timing data,
-                   f9=undefined, f8=mfg. reserved */
-       u8 pad2;
-       union {
-               struct detailed_data_string str;
-               struct detailed_data_monitor_range range;
-               struct detailed_data_wpindex color;
-               struct std_timing timings[5];
-       } data;
-} __attribute__((packed));
-
-#define EDID_DETAIL_STD_MODES 0xfa
-#define EDID_DETAIL_MONITOR_CPDATA 0xfb
-#define EDID_DETAIL_MONITOR_NAME 0xfc
-#define EDID_DETAIL_MONITOR_RANGE 0xfd
-#define EDID_DETAIL_MONITOR_STRING 0xfe
-#define EDID_DETAIL_MONITOR_SERIAL 0xff
-
-struct detailed_timing {
-       u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */
-       union {
-               struct detailed_pixel_timing pixel_data;
-               struct detailed_non_pixel other_data;
-       } data;
-} __attribute__((packed));
-
-struct edid {
-       u8 header[8];
-       /* Vendor & product info */
-       u16 mfg_id; /* FIXME: byte order */
-       u16 prod_code; /* FIXME: byte order */
-       u32 serial; /* FIXME: byte order */
-       u8 mfg_week;
-       u8 mfg_year;
-       /* EDID version */
-       u8 version;
-       u8 revision;
-       /* Display info: */
-       /*   input definition */
-       u8 serration_vsync:1;
-       u8 sync_on_green:1;
-       u8 composite_sync:1;
-       u8 separate_syncs:1;
-       u8 blank_to_black:1;
-       u8 video_level:2;
-       u8 digital:1; /* bits below must be zero if set */
-       u8 width_cm;
-       u8 height_cm;
-       u8 gamma;
-       /*   feature support */
-       u8 default_gtf:1;
-       u8 preferred_timing:1;
-       u8 standard_color:1;
-       u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
-       u8 pm_active_off:1;
-       u8 pm_suspend:1;
-       u8 pm_standby:1;
-       /* Color characteristics */
-       u8 red_green_lo;
-       u8 black_white_lo;
-       u8 red_x;
-       u8 red_y;
-       u8 green_x;
-       u8 green_y;
-       u8 blue_x;
-       u8 blue_y;
-       u8 white_x;
-       u8 white_y;
-       /* Est. timings and mfg rsvd timings*/
-       struct est_timings established_timings;
-       /* Standard timings 1-8*/
-       struct std_timing standard_timings[8];
-       /* Detailing timings 1-4 */
-       struct detailed_timing detailed_timings[4];
-       /* Number of 128 byte ext. blocks */
-       u8 extensions;
-       /* Checksum */
-       u8 checksum;
-} __attribute__((packed));
-
+/* Valid EDID header has these bytes */
 static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
 
 /**
diff --git a/linux-core/drm_edid.h b/linux-core/drm_edid.h
new file mode 100644 (file)
index 0000000..0d2eeaa
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef __DRM_EDID_H__
+#define __DRM_EDID_H__
+
+#include <linux/types.h>
+
+#define EDID_LENGTH 128
+#define DDC_ADDR 0x50
+
+#ifdef BIG_ENDIAN
+#error "EDID structure is little endian, need big endian versions"
+#endif
+
+struct est_timings {
+       u8 t1;
+       u8 t2;
+       u8 mfg_rsvd;
+} __attribute__((packed));
+
+struct std_timing {
+       u8 hsize; /* need to multiply by 8 then add 248 */
+       u8 vfreq:6; /* need to add 60 */
+       u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
+} __attribute__((packed));
+
+/* If detailed data is pixel timing */
+struct detailed_pixel_timing {
+       u8 hactive_lo;
+       u8 hblank_lo;
+       u8 hblank_hi:4;
+       u8 hactive_hi:4;
+       u8 vactive_lo;
+       u8 vblank_lo;
+       u8 vblank_hi:4;
+       u8 vactive_hi:4;
+       u8 hsync_offset_lo;
+       u8 hsync_pulse_width_lo;
+       u8 vsync_pulse_width_lo:4;
+       u8 vsync_offset_lo:4;
+       u8 hsync_pulse_width_hi:2;
+       u8 hsync_offset_hi:2;
+       u8 vsync_pulse_width_hi:2;
+       u8 vsync_offset_hi:2;
+       u8 width_mm_lo;
+       u8 height_mm_lo;
+       u8 height_mm_hi:4;
+       u8 width_mm_hi:4;
+       u8 hborder;
+       u8 vborder;
+       u8 unknown0:1;
+       u8 vsync_positive:1;
+       u8 hsync_positive:1;
+       u8 separate_sync:2;
+       u8 stereo:1;
+       u8 unknown6:1;
+       u8 interlaced:1;
+} __attribute__((packed));
+
+/* If it's not pixel timing, it'll be one of the below */
+struct detailed_data_string {
+       u8 str[13];
+} __attribute__((packed));
+
+struct detailed_data_monitor_range {
+       u8 min_vfreq;
+       u8 max_vfreq;
+       u8 min_hfreq_khz;
+       u8 max_hfreq_khz;
+       u8 pixel_clock_mhz; /* need to multiply by 10 */
+       u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */
+       u8 hfreq_start_khz; /* need to multiply by 2 */
+       u8 c; /* need to divide by 2 */
+       u16 m; /* FIXME: byte order */
+       u8 k;
+       u8 j; /* need to divide by 2 */
+} __attribute__((packed));
+
+struct detailed_data_wpindex {
+       u8 white_y_lo:2;
+       u8 white_x_lo:2;
+       u8 pad:4;
+       u8 white_x_hi;
+       u8 white_y_hi;
+       u8 gamma; /* need to divide by 100 then add 1 */
+} __attribute__((packed));
+
+struct detailed_data_color_point {
+       u8 windex1;
+       u8 wpindex1[3];
+       u8 windex2;
+       u8 wpindex2[3];
+} __attribute__((packed));
+
+struct detailed_non_pixel {
+       u8 pad1;
+       u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
+                   fb=color point data, fa=standard timing data,
+                   f9=undefined, f8=mfg. reserved */
+       u8 pad2;
+       union {
+               struct detailed_data_string str;
+               struct detailed_data_monitor_range range;
+               struct detailed_data_wpindex color;
+               struct std_timing timings[5];
+       } data;
+} __attribute__((packed));
+
+#define EDID_DETAIL_STD_MODES 0xfa
+#define EDID_DETAIL_MONITOR_CPDATA 0xfb
+#define EDID_DETAIL_MONITOR_NAME 0xfc
+#define EDID_DETAIL_MONITOR_RANGE 0xfd
+#define EDID_DETAIL_MONITOR_STRING 0xfe
+#define EDID_DETAIL_MONITOR_SERIAL 0xff
+
+struct detailed_timing {
+       u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */
+       union {
+               struct detailed_pixel_timing pixel_data;
+               struct detailed_non_pixel other_data;
+       } data;
+} __attribute__((packed));
+
+struct edid {
+       u8 header[8];
+       /* Vendor & product info */
+       u16 mfg_id; /* FIXME: byte order */
+       u16 prod_code; /* FIXME: byte order */
+       u32 serial; /* FIXME: byte order */
+       u8 mfg_week;
+       u8 mfg_year;
+       /* EDID version */
+       u8 version;
+       u8 revision;
+       /* Display info: */
+       /*   input definition */
+       u8 serration_vsync:1;
+       u8 sync_on_green:1;
+       u8 composite_sync:1;
+       u8 separate_syncs:1;
+       u8 blank_to_black:1;
+       u8 video_level:2;
+       u8 digital:1; /* bits below must be zero if set */
+       u8 width_cm;
+       u8 height_cm;
+       u8 gamma;
+       /*   feature support */
+       u8 default_gtf:1;
+       u8 preferred_timing:1;
+       u8 standard_color:1;
+       u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+       u8 pm_active_off:1;
+       u8 pm_suspend:1;
+       u8 pm_standby:1;
+       /* Color characteristics */
+       u8 red_green_lo;
+       u8 black_white_lo;
+       u8 red_x;
+       u8 red_y;
+       u8 green_x;
+       u8 green_y;
+       u8 blue_x;
+       u8 blue_y;
+       u8 white_x;
+       u8 white_y;
+       /* Est. timings and mfg rsvd timings*/
+       struct est_timings established_timings;
+       /* Standard timings 1-8*/
+       struct std_timing standard_timings[8];
+       /* Detailing timings 1-4 */
+       struct detailed_timing detailed_timings[4];
+       /* Number of 128 byte ext. blocks */
+       u8 extensions;
+       /* Checksum */
+       u8 checksum;
+} __attribute__((packed));
+
+#endif /* __DRM_EDID_H__ */
index 58d6698..90c894e 100644 (file)
@@ -26,8 +26,6 @@
 
 #include <linux/i2c.h>
 #include "drmP.h"
-#include "drm.h"
-#include "drm_crtc.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
@@ -973,10 +971,115 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
        intel_crtc_load_lut(crtc);
 }
 
+/* Returns the clock of the currently programmed mode of the given pipe. */
+static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B);
+       u32 fp;
+       intel_clock_t clock;
+
+       if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
+               fp = I915_READ((pipe == 0) ? FPA0 : FPB0);
+       else
+               fp = I915_READ((pipe == 0) ? FPA1 : FPB1);
+
+       clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
+       clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
+       clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
+       if (IS_I9XX(dev)) {
+               clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
+                              DPLL_FPA01_P1_POST_DIV_SHIFT);
+
+               switch (dpll & DPLL_MODE_MASK) {
+               case DPLLB_MODE_DAC_SERIAL:
+                       clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ?
+                               5 : 10;
+                       break;
+               case DPLLB_MODE_LVDS:
+                       clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ?
+                               7 : 14;
+                       break;
+               default:
+                       DRM_DEBUG("Unknown DPLL mode %08x in programmed "
+                                 "mode\n", (int)(dpll & DPLL_MODE_MASK));
+                       return 0;
+               }
+
+               /* XXX: Handle the 100Mhz refclk */
+               i9xx_clock(96000, &clock);
+       } else {
+               bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
+
+               if (is_lvds) {
+                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
+                                      DPLL_FPA01_P1_POST_DIV_SHIFT);
+                       clock.p2 = 14;
+
+                       if ((dpll & PLL_REF_INPUT_MASK) ==
+                           PLLB_REF_INPUT_SPREADSPECTRUMIN) {
+                               /* XXX: might not be 66MHz */
+                               i8xx_clock(66000, &clock);
+                       } else
+                               i8xx_clock(48000, &clock);              
+               } else {
+                       if (dpll & PLL_P1_DIVIDE_BY_TWO)
+                               clock.p1 = 2;
+                       else {
+                               clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
+                                           DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
+                       }
+                       if (dpll & PLL_P2_DIVIDE_BY_4)
+                               clock.p2 = 4;
+                       else
+                               clock.p2 = 2;
+
+                       i8xx_clock(48000, &clock);
+               }
+       }
+
+       /* XXX: It would be nice to validate the clocks, but we can't reuse
+        * i830PllIsValid() because it relies on the xf86_config output
+        * configuration being accurate, which it isn't necessarily.
+        */
+
+       return clock.dot;
+}
+
+/** Returns the currently programmed mode of the given pipe. */
 struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev,
                                             struct drm_crtc *crtc)
 {
-       return NULL;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       struct drm_display_mode *mode;
+       int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
+       int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
+       int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
+       int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
+
+       mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+       if (!mode)
+               return NULL;
+
+       mode->clock = intel_crtc_clock_get(dev, crtc);
+       mode->hdisplay = (htot & 0xffff) + 1;
+       mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
+       mode->hsync_start = (hsync & 0xffff) + 1;
+       mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
+       mode->vdisplay = (vtot & 0xffff) + 1;
+       mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
+       mode->vsync_start = (vsync & 0xffff) + 1;
+       mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
+       /* FIXME: pull name generation into a common routine */
+       snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay,
+                mode->vdisplay);
+       drm_mode_set_crtcinfo(mode, 0);
+
+       return mode;
 }
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -1017,7 +1120,7 @@ void intel_crtc_init(drm_device_t *dev, int pipe)
        crtc->driver_private = intel_crtc;
 }
 
-int intel_output_clones (drm_device_t *dev, int type_mask)
+int intel_output_clones(drm_device_t *dev, int type_mask)
 {
        int index_mask = 0;
        struct drm_output *output;
@@ -1039,9 +1142,11 @@ static void intel_setup_outputs(drm_device_t *dev)
 
        intel_crt_init(dev);
 
+#if 0
        /* Set up integrated LVDS */
        if (IS_MOBILE(dev) && !IS_I830(dev))
                intel_lvds_init(dev);
+#endif
 
        if (IS_I9XX(dev)) {
                intel_sdvo_init(dev, SDVOB);
@@ -1105,6 +1210,7 @@ void intel_modeset_init(drm_device_t *dev)
        intel_setup_outputs(dev);
 
        drm_initial_config(dev, false);
+       drm_set_desired_modes(dev);
 }
 
 void intel_modeset_cleanup(drm_device_t *dev)
index 7b02d35..0675e06 100644 (file)
@@ -71,4 +71,7 @@ extern void intel_lvds_init(drm_device_t *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_output_prepare (struct drm_output *output);
 extern void intel_output_commit (struct drm_output *output);
+extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev,
+                                                   struct drm_crtc *crtc);
+
 #endif /* __INTEL_DRV_H__ */
index 7527dfc..4638fb3 100644 (file)
@@ -31,6 +31,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc.h"
+#include "drm_edid.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
@@ -262,7 +263,7 @@ static int intel_lvds_get_modes(struct drm_output *output)
        struct intel_output *intel_output = output->driver_private;
        struct drm_device *dev = output->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_monitor_info *edid_mon;
+       struct edid *edid_info;
        int ret = 0;
 
        intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
@@ -276,23 +277,29 @@ static int intel_lvds_get_modes(struct drm_output *output)
        ret = intel_ddc_get_modes(output);
        if (ret)
                return ret;
-#if 0
+
+       /* Didn't get an EDID */
        if (!output->monitor_info) {
-               edid_mon = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL);
-               if (edid_mon) {
-                       /* Set wide sync ranges so we get all modes
-                        * handed to valid_mode for checking
-                        */
-                       edid_mon->det_mon[0].type = DS_RANGES;
-                       edid_mon->det_mon[0].section.ranges.min_v = 0;
-                       edid_mon->det_mon[0].section.ranges.max_v = 200;
-                       edid_mon->det_mon[0].section.ranges.min_h = 0;
-                       edid_mon->det_mon[0].section.ranges.max_h = 200;
-           
-                       output->monitor_info = edid_mon;
-               }
+               struct detailed_data_monitor_range *edid_range;
+               edid_info = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL);
+               if (!edid_info)
+                       goto out;
+
+               edid_info->detailed_timings[0].data.other_data.type =
+                       EDID_DETAIL_MONITOR_RANGE;
+               edid_range = &edid_info->detailed_timings[0].data.other_data.data.range;
+
+               /* Set wide sync ranges so we get all modes
+                * handed to valid_mode for checking
+                */
+               edid_range->min_vfreq = 0;
+               edid_range->max_vfreq = 200;
+               edid_range->min_hfreq_khz = 0;
+               edid_range->max_hfreq_khz = 200;
+               output->monitor_info = edid_info;
        }
-#endif
+
+out:
        if (dev_priv->panel_fixed_mode != NULL) {
                struct drm_display_mode *mode =
                        drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
@@ -322,13 +329,19 @@ static const struct drm_output_funcs intel_lvds_output_funcs = {
        .cleanup = intel_lvds_destroy
 };
 
-void
-intel_lvds_init(struct drm_device *dev)
+/**
+ * intel_lvds_init - setup LVDS outputs on this device
+ * @dev: drm device
+ *
+ * Create the output, register the LVDS DDC bus, and try to figure out what
+ * modes we can display on the LVDS panel (if present).
+ */
+void intel_lvds_init(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_output *output;
        struct intel_output *intel_output;
-       struct drm_display_mode *modes, scan, bios_mode;
+       struct drm_display_mode *scan; /* *modes, *bios_mode; */
 
        output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS");
        if (!output)
@@ -356,37 +369,43 @@ intel_lvds_init(struct drm_device *dev)
                        break;
        }
 
-       if (scan != NULL)
+       if (scan)
                dev_priv->panel_fixed_mode = scan;
 
-#if 0
        /*
         * If we didn't get EDID, try checking if the panel is already turned
         * on.  If so, assume that whatever is currently programmed is the
         * correct mode.
         */
-       if (dev_priv->panel_fixed_mode == NULL) {
+       if (!dev_priv->panel_fixed_mode) {
                u32 lvds = I915_READ(LVDS);
                int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-               struct drm_crtc_config *crtc_config = dev->crtc_config;
-               struct drm_crtc *crtc = crtc_config->crtc[pipe];
-
-               if (lvds & LVDS_PORT_EN) {
-                       dev_priv->panel_fixed_mode = intel_crtc_mode_get(pScrn, crtc);
-                       if (dev_priv->panel_fixed_mode != NULL)
-                               dev_priv->panel_fixed_mode->type |= M_T_PREFERRED;
+               struct drm_crtc_config *crtc_config = &dev->crtc_config;
+               struct drm_crtc *crtc;
+               /* FIXME: need drm_crtc_from_pipe */
+               //crtc = drm_crtc_from_pipe(crtc_config, pipe);
+               
+               if (lvds & LVDS_PORT_EN && 0) {
+                       dev_priv->panel_fixed_mode =
+                               intel_crtc_mode_get(dev, crtc);
+                       if (dev_priv->panel_fixed_mode)
+                               dev_priv->panel_fixed_mode->type |=
+                                       DRM_MODE_TYPE_PREFERRED;
                }
        }
 
-       /* Get the LVDS fixed mode out of the BIOS.  We should support LVDS with
-        * the BIOS being unavailable or broken, but lack the configuration options
-        * for now.
+/* No BIOS poking yet... */
+#if 0
+       /* Get the LVDS fixed mode out of the BIOS.  We should support LVDS
+        * with the BIOS being unavailable or broken, but lack the
+        * configuration options for now.
         */
        bios_mode = intel_bios_get_panel_mode(pScrn);
        if (bios_mode != NULL) {
                if (dev_priv->panel_fixed_mode != NULL) {
                        if (dev_priv->debug_modes &&
-                           !xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode))
+                           !xf86ModesEqual(dev_priv->panel_fixed_mode,
+                                           bios_mode))
                        {
                                xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                                           "BIOS panel mode data doesn't match probed data, "
@@ -439,35 +458,3 @@ intel_lvds_init(struct drm_device *dev)
 #endif
        return;
 }
-
-#if 0
-/**
- * intel_lvds_init - setup LVDS outputs on this device
- * @dev: drm device
- *
- * Create the output, register the LVDS DDC bus, and try to figure out what
- * modes we can display on the LVDS panel (if present).
- */
-void intel_lvds_init(drm_device_t *dev)
-{
-       struct drm_output *output;
-       struct intel_output *intel_output;
-       int modes;
-
-       output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS");
-       if (!output)
-               return;
-
-       intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL);
-       if (!intel_output) {
-               drm_output_destroy(output);
-               return;
-       }
-
-       intel_output->type = INTEL_OUTPUT_LVDS;
-       output->driver_private = intel_output;
-       output->subpixel_order = SubPixelHorizontalRGB;
-       output->interlace_allowed = 0;
-       output->doublescan_allowed = 0;
-}
-#endif