Finish bringing in LVDS code, re-add to Makefile. Needed other changes too:
- 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.hmain
parent
c446bf50e3
commit
183cbd92dd
|
@ -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
|
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
|
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-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
|
intel_sdvo.o intel_modes.o intel_i2c.o
|
||||||
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
|
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
|
||||||
nouveau_object.o nouveau_irq.o \
|
nouveau_object.o nouveau_irq.o \
|
||||||
|
|
|
@ -369,6 +369,7 @@ struct drm_output {
|
||||||
/* xf86MonPtr MonInfo; */
|
/* xf86MonPtr MonInfo; */
|
||||||
enum subpixel_order subpixel_order;
|
enum subpixel_order subpixel_order;
|
||||||
int mm_width, mm_height;
|
int mm_width, mm_height;
|
||||||
|
struct edid *monitor_info;
|
||||||
char name[DRM_OUTPUT_LEN];
|
char name[DRM_OUTPUT_LEN];
|
||||||
const struct drm_output_funcs *funcs;
|
const struct drm_output_funcs *funcs;
|
||||||
void *driver_private;
|
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,
|
extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
|
||||||
int adjust_flags);
|
int adjust_flags);
|
||||||
extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
|
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__ */
|
#endif /* __DRM_CRTC_H__ */
|
||||||
|
|
||||||
|
|
|
@ -4,181 +4,14 @@
|
||||||
*
|
*
|
||||||
* DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
|
* DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
|
||||||
* FB layer.
|
* FB layer.
|
||||||
|
* Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
|
||||||
*/
|
*/
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/i2c-algo-bit.h>
|
#include <linux/i2c-algo-bit.h>
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
|
#include "drm_edid.h"
|
||||||
|
|
||||||
#define EDID_LENGTH 128
|
/* Valid EDID header has these bytes */
|
||||||
#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));
|
|
||||||
|
|
||||||
static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
|
static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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__ */
|
|
@ -26,8 +26,6 @@
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "drm.h"
|
|
||||||
#include "drm_crtc.h"
|
|
||||||
#include "intel_drv.h"
|
#include "intel_drv.h"
|
||||||
#include "i915_drm.h"
|
#include "i915_drm.h"
|
||||||
#include "i915_drv.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);
|
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_display_mode *intel_crtc_mode_get(drm_device_t *dev,
|
||||||
struct drm_crtc *crtc)
|
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 = {
|
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;
|
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;
|
int index_mask = 0;
|
||||||
struct drm_output *output;
|
struct drm_output *output;
|
||||||
|
@ -1039,9 +1142,11 @@ static void intel_setup_outputs(drm_device_t *dev)
|
||||||
|
|
||||||
intel_crt_init(dev);
|
intel_crt_init(dev);
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* Set up integrated LVDS */
|
/* Set up integrated LVDS */
|
||||||
if (IS_MOBILE(dev) && !IS_I830(dev))
|
if (IS_MOBILE(dev) && !IS_I830(dev))
|
||||||
intel_lvds_init(dev);
|
intel_lvds_init(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (IS_I9XX(dev)) {
|
if (IS_I9XX(dev)) {
|
||||||
intel_sdvo_init(dev, SDVOB);
|
intel_sdvo_init(dev, SDVOB);
|
||||||
|
@ -1105,6 +1210,7 @@ void intel_modeset_init(drm_device_t *dev)
|
||||||
intel_setup_outputs(dev);
|
intel_setup_outputs(dev);
|
||||||
|
|
||||||
drm_initial_config(dev, false);
|
drm_initial_config(dev, false);
|
||||||
|
drm_set_desired_modes(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void intel_modeset_cleanup(drm_device_t *dev)
|
void intel_modeset_cleanup(drm_device_t *dev)
|
||||||
|
|
|
@ -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_crtc_load_lut(struct drm_crtc *crtc);
|
||||||
extern void intel_output_prepare (struct drm_output *output);
|
extern void intel_output_prepare (struct drm_output *output);
|
||||||
extern void intel_output_commit (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__ */
|
#endif /* __INTEL_DRV_H__ */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
#include "drm_crtc.h"
|
#include "drm_crtc.h"
|
||||||
|
#include "drm_edid.h"
|
||||||
#include "intel_drv.h"
|
#include "intel_drv.h"
|
||||||
#include "i915_drm.h"
|
#include "i915_drm.h"
|
||||||
#include "i915_drv.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 intel_output *intel_output = output->driver_private;
|
||||||
struct drm_device *dev = output->dev;
|
struct drm_device *dev = output->dev;
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
struct drm_monitor_info *edid_mon;
|
struct edid *edid_info;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
|
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);
|
ret = intel_ddc_get_modes(output);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
#if 0
|
|
||||||
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;
|
/* Didn't get an EDID */
|
||||||
}
|
if (!output->monitor_info) {
|
||||||
|
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) {
|
if (dev_priv->panel_fixed_mode != NULL) {
|
||||||
struct drm_display_mode *mode =
|
struct drm_display_mode *mode =
|
||||||
drm_mode_duplicate(dev, dev_priv->panel_fixed_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
|
.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;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
struct drm_output *output;
|
struct drm_output *output;
|
||||||
struct intel_output *intel_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");
|
output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS");
|
||||||
if (!output)
|
if (!output)
|
||||||
|
@ -356,37 +369,43 @@ intel_lvds_init(struct drm_device *dev)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scan != NULL)
|
if (scan)
|
||||||
dev_priv->panel_fixed_mode = scan;
|
dev_priv->panel_fixed_mode = scan;
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
/*
|
||||||
* If we didn't get EDID, try checking if the panel is already turned
|
* 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
|
* on. If so, assume that whatever is currently programmed is the
|
||||||
* correct mode.
|
* correct mode.
|
||||||
*/
|
*/
|
||||||
if (dev_priv->panel_fixed_mode == NULL) {
|
if (!dev_priv->panel_fixed_mode) {
|
||||||
u32 lvds = I915_READ(LVDS);
|
u32 lvds = I915_READ(LVDS);
|
||||||
int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
|
int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
|
||||||
struct drm_crtc_config *crtc_config = dev->crtc_config;
|
struct drm_crtc_config *crtc_config = &dev->crtc_config;
|
||||||
struct drm_crtc *crtc = crtc_config->crtc[pipe];
|
struct drm_crtc *crtc;
|
||||||
|
/* FIXME: need drm_crtc_from_pipe */
|
||||||
|
//crtc = drm_crtc_from_pipe(crtc_config, pipe);
|
||||||
|
|
||||||
if (lvds & LVDS_PORT_EN) {
|
if (lvds & LVDS_PORT_EN && 0) {
|
||||||
dev_priv->panel_fixed_mode = intel_crtc_mode_get(pScrn, crtc);
|
dev_priv->panel_fixed_mode =
|
||||||
if (dev_priv->panel_fixed_mode != NULL)
|
intel_crtc_mode_get(dev, crtc);
|
||||||
dev_priv->panel_fixed_mode->type |= M_T_PREFERRED;
|
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
|
/* No BIOS poking yet... */
|
||||||
* the BIOS being unavailable or broken, but lack the configuration options
|
#if 0
|
||||||
* for now.
|
/* 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);
|
bios_mode = intel_bios_get_panel_mode(pScrn);
|
||||||
if (bios_mode != NULL) {
|
if (bios_mode != NULL) {
|
||||||
if (dev_priv->panel_fixed_mode != NULL) {
|
if (dev_priv->panel_fixed_mode != NULL) {
|
||||||
if (dev_priv->debug_modes &&
|
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,
|
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
|
||||||
"BIOS panel mode data doesn't match probed data, "
|
"BIOS panel mode data doesn't match probed data, "
|
||||||
|
@ -439,35 +458,3 @@ intel_lvds_init(struct drm_device *dev)
|
||||||
#endif
|
#endif
|
||||||
return;
|
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
|
|
||||||
|
|
Loading…
Reference in New Issue