diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/Documentation/drm/modesetting.txt linux-2.6.21-rc4-modesetting/Documentation/drm/modesetting.txt --- linux-2.6.21-rc4/Documentation/drm/modesetting.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/Documentation/drm/modesetting.txt 2007-03-21 08:46:47.000000000 -0700 @@ -0,0 +1,82 @@ +Video modesetting and multihead support in the kernel +----------------------------------------------------- + +Why in the kernel? + +There are several reasons to pull modesetting and proper multihead support +into the kernel: + - suspend/resume + - debugging (e.g. panic) + - non-X uses + - more reliable VT switch +Each of the above is covered in more detail below. + +Suspend/resume +-------------- +Currently, the kernel has to rely on an external application (X, vbetool, etc.) +to reset video devices to the proper state after resume. If one of these +processes has trouble or crashes during or shortly after resume, the system +will become unusable, with little indication as to why (see Debugging below). +Putting code into the kernel to perform low level modesetting (i.e. without +video BIOS support) will allow the kernel to resume to the correct mode +automatically and more quickly than would be possible otherwise. + +Debugging +--------- +As mentioned above, if something goes wrong with modesetting during resume, the +user has very little indication of where things went wrong. Likewise, if a +panic or oops occurs while an application like X is running, the user will +experience a hard hang, rather than the much more pleasant "blue penguin of +death" (to be coded). When a panic type event occurs, the kernel could set an +appropriate mode, ideally one that can fit lots of panic data or long +backtraces. Another possibility is multihead debugging: one display could run +the user's applications (i.e. a "normal" display) while a secondary display +could run a system level debugger, allowing the user to stop the machine, +investigate memory, step through programs, etc. + +Non-X uses +---------- +As it stands, non-X based applications wanting to use video devices have two +options: either take over the hardware themselves or use the existing kernel +fb layer. The former is obviously a tall order, while the latter isn't +featureful enough to expose multiple outputs, perform per-device locking so +that multiple clients can share the device, etc. A kernel based modsetting +and multihead API would make developing such applications much easier. + +VT switch +--------- +Currently, the kernel relies on an external program to restore the graphics +state when a VT switch occurs. This doesn't always work, with similar results +to the suspend/resume case: an apparently hung or unusable machine. Of +course, the kernel can't unconditionally preempt the graphics device to set +a new mode, but having modesetting in the kernel will give it a much better +chance of coordinating with the DRM command dispatch code to find a good time +to set a new mode. + +Interfaces +---------- +The kernel DRM layer manages the output devices, available modes, and calls +into the low level DRM drivers to set modes and probe outputs devices for +attached displays, much like the X server's internal RandR 1.2 APIs. It also +provides userspace with an interface to these functions, based on the X +server's external RandR 1.2 APIs. + +Implementation plan +------------------- +Port output detection and modesetting code from the X server's Intel driver to +the kernel's Intel DRM driver. Get output detection and mode detection +working, then add the high level management layer to the DRM and start adding +support to other low level drivers. + - port VGA output code to the Intel DRM driver + - set modes on an external VGA device using an ioctl (throwaway) + - need i2c layer for DDC? + - port other output management code from the X driver + - need i2c layer + - write a new DRM layer to manage and enumerate output devices and displays + - modify Intel code to use new layer + - modify X server to use new API + - float on lkml + - revise, add support for other drivers, revise X code + +Structure +--------- diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/drm_crtc.c linux-2.6.21-rc4-modesetting/drivers/char/drm/drm_crtc.c --- linux-2.6.21-rc4/drivers/char/drm/drm_crtc.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/drm_crtc.c 2007-03-21 09:33:54.000000000 -0700 @@ -0,0 +1,56 @@ +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" + +static DEFINE_SPINLOCK(drm_modes_lock); +static LIST_HEAD(drm_modes); + +static DEFINE_SPINLOCK(drm_output_lock); +static LIST_HEAD(drm_outputs); + +struct drm_output *drm_output_create(drm_device_t *dev, + const struct drm_output_funcs *funcs, + const char *name) +{ + struct drm_output *output; + + if (!name) { + dev_printk(KERN_ERR, &dev->pdev->dev, "%s: name missing.\n", + __FUNCTION__); + return NULL; + } + + output = kmalloc(sizeof(struct drm_output), GFP_KERNEL); + if (!output) + return NULL; + + output->dev = dev; + output->funcs = funcs; + strncpy(output->name, name, DRM_OUTPUT_LEN); + output->name[DRM_OUTPUT_LEN - 1] = 0; + output->subpixel_order = SubPixelUnknown; + /* randr_output? */ + /* output_set_monitor(output)? */ + /* check for output_ignored(output)? */ + + spin_lock(&drm_output_lock); + list_add(&output->head, &drm_outputs); + spin_unlock(&drm_output_lock); + + return output; +} +EXPORT_SYMBOL(drm_output_create); + +void drm_output_destroy(struct drm_output *output) +{ + spin_lock(&drm_output_lock); + list_del(&output->head); + spin_unlock(&drm_output_lock); + kfree(output); +} +EXPORT_SYMBOL(drm_output_destroy); + +bool drm_initial_config(drm_device_t *dev, bool can_grow) +{ + return 0; +} diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/drm_crtc.h linux-2.6.21-rc4-modesetting/drivers/char/drm/drm_crtc.h --- linux-2.6.21-rc4/drivers/char/drm/drm_crtc.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/drm_crtc.h 2007-03-21 08:41:51.000000000 -0700 @@ -0,0 +1,350 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2007 Intel Corporation + * Jesse Barnes + */ +#ifndef __DRM_CRTC_H__ +#define __DRM_CRTC_H__ + +#include +#include +#include "drmP.h" +#include "drm.h" + +/* + * Note on terminology: here, for brevity and convenience, we refer to output + * control chips as 'CRTCS'. They can control any type of output, VGA, LVDS, + * DVI, etc. And 'screen' refers to the whole of the visible display, which + * may span multiple monitors (and therefore multiple CRTC and output + * structures). + */ + +enum drm_mode_status { + MODE_OK = 0, /* Mode OK */ + MODE_HSYNC, /* hsync out of range */ + MODE_VSYNC, /* vsync out of range */ + MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_BAD_WIDTH, /* requires an unsupported linepitch */ + MODE_NOMODE, /* no mode with a maching name */ + MODE_NO_INTERLACE, /* interlaced mode not supported */ + MODE_NO_DBLESCAN, /* doublescan mode not supported */ + MODE_NO_VSCAN, /* multiscan mode not supported */ + MODE_MEM, /* insufficient video memory */ + MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ + MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ + MODE_MEM_VIRT, /* insufficient video memory given virtual size */ + MODE_NOCLOCK, /* no fixed clock available */ + MODE_CLOCK_HIGH, /* clock required is too high */ + MODE_CLOCK_LOW, /* clock required is too low */ + MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ + MODE_BAD_HVALUE, /* horizontal timing was out of range */ + MODE_BAD_VVALUE, /* vertical timing was out of range */ + MODE_BAD_VSCAN, /* VScan value out of range */ + MODE_HSYNC_NARROW, /* horizontal sync too narrow */ + MODE_HSYNC_WIDE, /* horizontal sync too wide */ + MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ + MODE_HBLANK_WIDE, /* horizontal blanking too wide */ + MODE_VSYNC_NARROW, /* vertical sync too narrow */ + MODE_VSYNC_WIDE, /* vertical sync too wide */ + MODE_VBLANK_NARROW, /* vertical blanking too narrow */ + MODE_VBLANK_WIDE, /* vertical blanking too wide */ + MODE_PANEL, /* exceeds panel dimensions */ + MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ + MODE_ONE_WIDTH, /* only one width is supported */ + MODE_ONE_HEIGHT, /* only one height is supported */ + MODE_ONE_SIZE, /* only one resolution is supported */ + MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ + MODE_BAD = -2, /* unspecified reason */ + MODE_ERROR = -1 /* error condition */ +}; + +#define DRM_DISPLAY_MODE_LEN 32 + +struct drm_display_mode { + struct list_head head; + char name[DRM_DISPLAY_MODE_LEN]; + enum drm_mode_status status; + int type; + + /* Proposed mode values */ + int clock; + int hdisplay; + int hsync_start; + int hsync_end; + int htotal; + int hskew; + int vdisplay; + int vsync_start; + int vsync_end; + int vtotal; + int vscan; + unsigned int flags; + + /* Actual mode we give to hw */ + int clock_index; + int synth_clock; + int crtc_hdisplay; + int crtc_hblank_start; + int crtc_hsync_start; + int crtc_hblank_end; + int crtc_htotal; + int crtc_hskew; + int crtc_vdisplay; + int crtc_vblank_start; + int crtc_vblank_end; + int crtc_vsync_start; + int crtc_vsync_end; + int crtc_vtotal; + int crtc_hadjusted; + int crtc_vadjusted; + + /* Driver private mode info */ + int private_size; + int *private; + int private_flags; + + float hsync, vrefresh; +}; + +enum drm_output_status { + output_status_connected, + output_status_disconnected, + output_status_unknown, +}; + +enum subpixel_order { + SubPixelUnknown = 0, + SubPixelHorizontalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalRGB, + SubPixelVerticalBGR, + SubPixelNone, +}; + +struct drm_crtc; +struct drm_output; + +/** + * drm_crtc_funcs - control CRTCs for a given device + * @dpms: control display power levels + * @save: save CRTC state + * @resore: restore CRTC state + * @lock: lock the CRTC + * @unlock: unlock the CRTC + * @shadow_allocate: allocate shadow pixmap + * @shadow_create: create shadow pixmap for rotation support + * @shadow_destroy: free shadow pixmap + * @mode_fixup: fixup proposed mode + * @mode_set: set the desired mode on the CRTC + * @gamma_set: specify color ramp for CRTC + * @cleanup: cleanup driver private state prior to close + * + * The drm_crtc_funcs structure is the central CRTC management structure + * in the DRM. Each CRTC controls one or more outputs (note that the name + * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. + * outputs, not just CRTs). + * + * Each driver is responsible for filling out this structure at startup time, + * in addition to providing other modesetting features, like i2c and DDC + * bus accessors. + */ +struct drm_crtc_funcs { + /* + * Control power levels on the CRTC. If the mode passed in is + * unsupported, the provider must use the next lowest power level. + */ + void (*dpms)(struct drm_crtc *crtc, int mode); + + /* JJJ: Are these needed? */ + /* Save CRTC state */ + void (*save)(struct drm_crtc *crtc); /* suspend? */ + /* Restore CRTC state */ + void (*restore)(struct drm_crtc *crtc); /* resume? */ + bool (*lock)(struct drm_crtc *crtc); + void (*unlock)(struct drm_crtc *crtc); + + /* Rotation related shadow buffers */ + void (*shadow_allocate)(struct drm_crtc *crtc, int width, int height); + void *(*shadow_create)(struct drm_crtc *crtc, void *data, int width, + int height); + void (*shadow_destroy)(struct drm_crtc *crtc, void *pPixmap, + void *data); + + /* Provider can fixup or change mode timings before modeset occurs */ + bool (*mode_fixup)(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /* Actually set the mode */ + void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, int x, int y); + /* Set gamma on the CRTC */ + void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, + int size); + /* Driver cleanup routine */ + void (*cleanup)(struct drm_crtc *crtc); +}; + +/** + * drm_crtc - central CRTC control structure + * @enabled: is this CRTC enabled? + * @x: x position on screen + * @y: y position on screen + * @desired_mode: new desired mode + * @desired_x: desired x for desired_mode + * @desired_y: desired y for desired_mode + * @funcs: CRTC control functions + * @driver_private: arbitrary driver data + * + * Each CRTC may have one or more outputs associated with it. This structure + * allows the CRTC to be controlled. + */ +struct drm_crtc { + drm_device_t *dev; + bool enabled; + + /* JJJ: are these needed? */ + bool cursor_in_range; + bool cursor_shown; + + struct drm_display_mode mode; + + /* + Rotation rotation; + PixmapPtr rotatedPixmap; + void *rotatedData; + */ + + int x, y; + struct drm_display_mode desired_mode; + /* Rotation desiredRotation; */ + int desired_x, desired_y; + const struct drm_crtc_funcs *funcs; + void *driver_private; + + /* RRCrtcPtr randr_crtc? */ +}; + +/** + * drm_output_funcs - control outputs on a given device + * @init: setup this output + * @dpms: set power state (see drm_crtc_funcs above) + * @save: save output state + * @restore: restore output state + * @mode_valid: is this mode valid on the given output? + * @mode_fixup: try to fixup proposed mode for this output + * @mode_set: set this mode + * @detect: is this output active? + * @get_modes: get mode list for this output + * @set_property: property for this output may need update + * @cleanup: output is going away, cleanup + * + * Each CRTC may have one or more outputs attached to it. The functions + * below allow the core DRM code to control outputs, enumerate available modes, + * etc. + */ +struct drm_output_funcs { + void (*init)(struct drm_output *output); + void (*dpms)(struct drm_output *output, int mode); + void (*save)(struct drm_output *output); + void (*restore)(struct drm_output *output); + void (*mode_valid)(struct drm_output *output, + struct drm_display_mode *mode); + bool (*mode_fixup)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*mode_set)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + enum drm_output_status (*detect)(struct drm_output *output); + struct drm_display_mode *(*get_modes)(struct drm_output *output); + /* JJJ: type checking for properties via property value type */ + bool (*set_property)(struct drm_output *output, int prop, void *val); + void (*cleanup)(struct drm_output *output); +}; + +#define DRM_OUTPUT_LEN 32 +/** + * drm_output - central DRM output control structure + * @crtc: CRTC this output is currently connected to, NULL if none + * @possible_crtcs: bitmap of CRTCS this output could be attached to + * @possible_clones: bitmap of possible outputs this output could clone + * @interlace_allowed: can this output handle interlaced modes? + * @doublescan_allowed: can this output handle doublescan? + * @available_modes: modes available on this output (from get_modes() + user) + * @initial_x: initial x position for this output + * @initial_y: initial y position for this output + * @status: output connected? + * @subpixel_order: for this output + * @mm_width: displayable width of output in mm + * @mm_height: displayable height of output in mm + * @name: name of output (should be one of a few standard names) + * @funcs: output control functions + * @driver_private: private driver data + * + * Each output may be connected to one or more CRTCs, or may be clonable by + * another output if they can share a CRTC. Each output also has a specific + * position in the broader display (referred to as a 'screen' though it could + * span multiple monitors). + */ +struct drm_output { + drm_device_t *dev; + struct list_head head; + struct drm_crtc *crtc; + unsigned long possible_crtcs; + unsigned long possible_clones; + bool interlace_allowed; + bool doublescan_allowed; + struct drm_display_mode *available_modes; + /* + OptionInfoPtr options; + XF86ConfMonitorPtr conf_monitor; + */ + int initial_x, initial_y; + /* Rotation initial_rotation */ + enum drm_output_status status; + /* xf86MonPtr MonInfo; */ + enum subpixel_order subpixel_order; + int mm_width, mm_height; + char name[DRM_OUTPUT_LEN]; + const struct drm_output_funcs *funcs; + void *driver_private; + /* RROutputPtr randr_output? */ +}; + +/** + * struct drm_crtc_config_funcs - configure CRTCs for a given screen layout + * @resize: adjust CRTCs as necessary for the proposed layout + * + * Currently only a resize hook is available. DRM will call back into the + * driver with a new screen width and height. If the driver can't support + * the proposed size, it can return false. Otherwise it should adjust + * the CRTC<->output mappings as needed and update its view of the screen. + */ +struct drm_crtc_config_funcs { + bool (*resize)(drm_device_t *dev, int width, int height); +}; + +/** + * drm_crtc_config - CRTC configuration control structure + * + */ +struct drm_crtc_config { + int num_output; + struct drm_output *output; + /* int compat_output? */ + int num_crtc; + struct drm_crtc *crtc; + int min_width, min_height; + int max_width, max_height; + /* DamagePtr rotationDamage? */ + /* DGA stuff? */ + struct drm_crtc_config_funcs *funcs; +}; + +struct drm_output *drm_output_create(drm_device_t *dev, + const struct drm_output_funcs *funcs, + const char *name); +void drm_output_destroy(struct drm_output *output); + +#endif /* __DRM_CRTC_H__ */ diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/i915_dma.c linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_dma.c --- linux-2.6.21-rc4/drivers/char/drm/i915_dma.c 2007-03-15 17:20:01.000000000 -0700 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_dma.c 2007-03-22 17:48:21.000000000 -0700 @@ -31,11 +31,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ - dev->pci_device == 0x2982 || \ - dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2) - /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/i915_drm.h linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_drm.h --- linux-2.6.21-rc4/drivers/char/drm/i915_drm.h 2007-03-15 17:20:01.000000000 -0700 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_drm.h 2007-03-21 08:41:51.000000000 -0700 @@ -142,6 +142,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_SET_VBLANK_PIPE 0x0d #define DRM_I915_GET_VBLANK_PIPE 0x0e #define DRM_I915_VBLANK_SWAP 0x0f +#define DRM_I915_BACKLIGHT 0x40 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -159,6 +160,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) +#define DRM_IOCTL_I915_BACKLIGHT DRM_IO(DRM_COMMAND_BASE + DRM_I915_BACKLIGHT) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/i915_drv.h linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_drv.h --- linux-2.6.21-rc4/drivers/char/drm/i915_drv.h 2007-03-15 17:20:01.000000000 -0700 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_drv.h 2007-03-21 14:13:01.000000000 -0700 @@ -30,6 +30,9 @@ #ifndef _I915_DRV_H_ #define _I915_DRV_H_ +#include +#include + /* General customization: */ @@ -208,6 +211,29 @@ extern int i915_wait_ring(drm_device_t * #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 +#define GPIOD 0x501c +#define GPIOE 0x5020 +#define GPIOF 0x5024 +#define GPIOG 0x5028 +#define GPIOH 0x502c +# define GPIO_CLOCK_DIR_MASK (1 << 0) +# define GPIO_CLOCK_DIR_IN (0 << 1) +# define GPIO_CLOCK_DIR_OUT (1 << 1) +# define GPIO_CLOCK_VAL_MASK (1 << 2) +# define GPIO_CLOCK_VAL_OUT (1 << 3) +# define GPIO_CLOCK_VAL_IN (1 << 4) +# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) +# define GPIO_DATA_DIR_MASK (1 << 8) +# define GPIO_DATA_DIR_IN (0 << 9) +# define GPIO_DATA_DIR_OUT (1 << 9) +# define GPIO_DATA_VAL_MASK (1 << 10) +# define GPIO_DATA_VAL_OUT (1 << 11) +# define GPIO_DATA_VAL_IN (1 << 12) +# define GPIO_DATA_PULLUP_DISABLE (1 << 13) + #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 #define SR01 1 @@ -216,6 +242,8 @@ extern int i915_wait_ring(drm_device_t * #define PPCR 0x61204 #define PPCR_ON (1<<0) +#define DVOA 0x61120 +#define DVOA_ON (1<<31) #define DVOB 0x61140 #define DVOB_ON (1<<31) #define DVOC 0x61160 @@ -294,4 +322,31 @@ extern int i915_wait_ring(drm_device_t * #define READ_BREADCRUMB(dev_priv) (((u32 *)(dev_priv->hw_status_page))[5]) +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +/** + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BLM_LEGACY_MODE (1 << 16) +/** + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) + +#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \ + (dev)->pci_device == 0x2982 || \ + (dev)->pci_device == 0x2992 || \ + (dev)->pci_device == 0x29A2) +#define IS_I830(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82830_CGC) +#define IS_845G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82845G_IG) + #endif diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/i915_irq.c linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_irq.c --- linux-2.6.21-rc4/drivers/char/drm/i915_irq.c 2007-03-15 17:20:01.000000000 -0700 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_irq.c 2007-03-22 17:46:02.000000000 -0700 @@ -576,6 +576,10 @@ void i915_driver_irq_preinstall(drm_devi I915_WRITE16(I915REG_HWSTAM, 0xfffe); I915_WRITE16(I915REG_INT_MASK_R, 0x0); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + extern void intel_lvds_init(drm_device_t *dev); + extern void intel_crt_init(drm_device_t *dev); + intel_lvds_init(dev); + intel_crt_init(dev); } void i915_driver_irq_postinstall(drm_device_t * dev) diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/intel_crt.c linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_crt.c --- linux-2.6.21-rc4/drivers/char/drm/intel_crt.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_crt.c 2007-03-22 17:47:46.000000000 -0700 @@ -0,0 +1,43 @@ +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Routines for controlling stuff on the analog port + */ +static const struct drm_output_funcs intel_crt_output_funcs; + +void intel_crt_init(drm_device_t *dev) +{ + struct drm_output *output; + struct intel_output *intel_output; + struct drm_display_mode *modes; + + output = drm_output_create (dev, &intel_crt_output_funcs, "VGA"); + + intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!intel_output) { + drm_output_destroy(output); + return; + } + + intel_output->type = INTEL_OUTPUT_ANALOG; + output->driver_private = intel_output; + output->interlace_allowed = 0; + output->doublescan_allowed = 0; + + /* Set up the DDC bus. */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return; + } + + modes = intel_ddc_get_modes(output); + intel_i2c_destroy(intel_output->ddc_bus); +} diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/intel_drv.h linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_drv.h --- linux-2.6.21-rc4/drivers/char/drm/intel_drv.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_drv.h 2007-03-21 14:28:49.000000000 -0700 @@ -0,0 +1,55 @@ +#ifndef __INTEL_DRV_H__ +#define __INTEL_DRV_H__ + +#include +#include +#include +#include "drm_crtc.h" + +/* + * Display related stuff + */ + +/* store information about an Ixxx DVO */ +/* The i830->i865 use multiple DVOs with multiple i2cs */ +/* the i915, i945 have a single sDVO i2c bus - which is different */ +#define MAX_OUTPUTS 6 + +#define INTEL_I2C_BUS_DVO 1 +#define INTEL_I2C_BUS_SDVO 2 + +/* these are outputs from the chip - integrated only + external chips are via DVO or SDVO output */ +#define INTEL_OUTPUT_UNUSED 0 +#define INTEL_OUTPUT_ANALOG 1 +#define INTEL_OUTPUT_DVO 2 +#define INTEL_OUTPUT_SDVO 3 +#define INTEL_OUTPUT_LVDS 4 +#define INTEL_OUTPUT_TVOUT 5 + +#define INTEL_DVO_CHIP_NONE 0 +#define INTEL_DVO_CHIP_LVDS 1 +#define INTEL_DVO_CHIP_TMDS 2 +#define INTEL_DVO_CHIP_TVOUT 4 + +struct intel_i2c_chan { + drm_device_t *drm_dev; /* for getting at dev. private (mmio etc.) */ + u32 reg; /* GPIO reg */ + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +struct intel_output { + int type; + struct intel_i2c_chan *i2c_bus; /* for control functions */ + struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ + bool load_detect_tmp; + void *dev_priv; +}; + +struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, + const char *name); +void intel_i2c_destroy(struct intel_i2c_chan *chan); +struct drm_display_mode *intel_ddc_get_modes(struct drm_output *output); + +#endif /* __INTEL_DRV_H__ */ diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/intel_i2c.c linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_i2c.c --- linux-2.6.21-rc4/drivers/char/drm/intel_i2c.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_i2c.c 2007-03-22 17:59:28.000000000 -0700 @@ -0,0 +1,163 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006 Intel Corporation + * Eric Anholt + * Jesse Barnes + */ + +#include +#include +#include +#include "drmP.h" +#include "drm.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Intel GPIO access functions + */ + +static int get_clock(void *data) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + val = I915_READ(chan->reg); + return ((val & GPIO_CLOCK_VAL_IN) != 0); +} + +static int get_data(void *data) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + val = I915_READ(chan->reg); + return ((val & GPIO_DATA_VAL_IN) != 0); +} + +static void set_clock(void *data, int state_high) +{ + struct intel_i2c_chan *chan = data; + drm_device_t *dev = chan->drm_dev; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 reserved = 0, clock_bits; + + /* On most chips, these bits must be preserved in software. */ + if (!IS_I830(dev) && !IS_845G(dev)) + reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); + + if (state_high) + clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; + else + clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | + GPIO_CLOCK_VAL_MASK; + I915_WRITE(chan->reg, reserved | clock_bits); +} + +static void set_data(void *data, int state_high) +{ + struct intel_i2c_chan *chan = data; + drm_device_t *dev = chan->drm_dev; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 reserved = 0, data_bits; + + /* On most chips, these bits must be preserved in software. */ + if (!IS_I830(dev) && !IS_845G(dev)) + reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); + + if (state_high) + data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; + else + data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | + GPIO_DATA_VAL_MASK; + + I915_WRITE(chan->reg, reserved | data_bits); +} + +/** + * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg + * @dev: DRM device + * @output: driver specific output device + * @reg: GPIO reg to use + * @name: name for this bus + * + * Creates and registers a new i2c bus with the Linux i2c layer, for use + * in output probing and control (e.g. DDC or SDVO control functions). + * + * Possible values for @reg include: + * %GPIOA + * %GPIOB + * %GPIOC + * %GPIOD + * %GPIOE + * %GPIOF + * %GPIOG + * %GPIOH + * see PRM for details on how these different busses are used. + */ +struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, + const char *name) +{ + struct intel_i2c_chan *chan; + + chan = kmalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); + if (!chan) + goto out_free; + + chan->drm_dev = dev; + chan->reg = reg; + snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_INTELFB; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &dev->pdev->dev; + chan->algo.setsda = set_data; + chan->algo.setscl = set_clock; + chan->algo.getsda = get_data; + chan->algo.getscl = get_clock; + chan->algo.udelay = 40; + chan->algo.timeout = usecs_to_jiffies(2200); + chan->algo.data = chan; + + printk(KERN_ERR "intel i2c channel setup\n"); + i2c_set_adapdata(&chan->adapter, chan); + + printk(KERN_ERR "adding i2c bus\n"); + if(i2c_bit_add_bus(&chan->adapter)) + goto out_free; + + printk(KERN_ERR "bus added, raising SCL and SDA\n"); + /* Raise SCL and SDA */ + set_data(chan, 1); + set_clock(chan, 1); + udelay(20); + + return chan; + +out_free: + kfree(chan); + return NULL; +} + +/** + * intel_i2c_destroy - unregister and free i2c bus resources + * @output: channel to free + * + * Unregister the adapter from the i2c layer, then free the structure. + */ +void intel_i2c_destroy(struct intel_i2c_chan *chan) +{ + if (!chan) + return; + + i2c_del_adapter(&chan->adapter); + kfree(chan); +} + + + diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/intel_lvds.c linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_lvds.c --- linux-2.6.21-rc4/drivers/char/drm/intel_lvds.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_lvds.c 2007-03-22 16:39:36.000000000 -0700 @@ -0,0 +1,106 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006 Intel Corporation + * Eric Anholt + * Jesse Barnes + */ + +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/** + * Sets the backlight level. + * + * \param level backlight level, from 0 to i830_lvds_get_max_backlight(). + */ +static void lvds_set_backlight(drm_device_t *dev, u32 level) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long blc_pwm_ctl; + + level &= BACKLIGHT_DUTY_CYCLE_MASK; + blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | + (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); +} + +/** + * Returns the maximum level of the backlight duty cycle field. + */ +static u32 lvds_get_max_backlight(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; +} + +int lvds_backlight(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + unsigned long dvoa_enabled, dvob_enabled, dvoc_enabled, lvds_enabled; + drm_i915_private_t *dev_priv = dev->dev_private; + + printk(KERN_ERR "max backlight value: %d\n", + lvds_get_max_backlight(dev)); + dvoa_enabled = I915_READ(DVOA); + dvob_enabled = I915_READ(DVOB); + dvoc_enabled = I915_READ(DVOC); + lvds_enabled = I915_READ(LVDS); + + printk(KERN_ERR "dvoa_enabled: 0x%08lx\n", dvoa_enabled); + printk(KERN_ERR "dvob_enabled: 0x%08lx\n", dvob_enabled); + printk(KERN_ERR "dvoc_enabled: 0x%08lx\n", dvoc_enabled); + printk(KERN_ERR "lvds_enabled: 0x%08lx\n", lvds_enabled); + printk(KERN_ERR "BLC_PWM_CTL: 0x%08x\n", I915_READ(BLC_PWM_CTL)); + + return 0; +} + +static const struct drm_output_funcs intel_lvds_output_funcs; + +/** + * 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; + struct drm_display_mode *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; + + intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return; + } + + modes = intel_ddc_get_modes(output); + intel_i2c_destroy(intel_output->ddc_bus); +} + diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/intel_modes.c linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_modes.c --- linux-2.6.21-rc4/drivers/char/drm/intel_modes.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/intel_modes.c 2007-03-22 17:41:15.000000000 -0700 @@ -0,0 +1,135 @@ +#include +#include "intel_drv.h" + +/* + * DDC/EDID probing rippped off from FB layer + */ + +#include "../../video/edid.h" +#define DDC_ADDR 0x50 + +static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter) +{ + unsigned char start = 0x0; + unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &start, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + .buf = buf, + } + }; + + if (!buf) { + dev_warn(&adapter->dev, "unable to allocate memory for EDID " + "block.\n"); + return NULL; + } + + if (i2c_transfer(adapter, msgs, 2) == 2) + return buf; + + dev_warn(&adapter->dev, "unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +static unsigned char *fb_ddc_read(struct i2c_adapter *adapter) +{ + struct i2c_algo_bit_data *algo_data = adapter->algo_data; + unsigned char *edid = NULL; + int i, j; + + algo_data->setscl(algo_data->data, 1); + algo_data->setscl(algo_data->data, 0); + + for (i = 0; i < 3; i++) { + /* For some old monitors we need the + * following process to initialize/stop DDC + */ + algo_data->setsda(algo_data->data, 0); + msleep(13); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 5; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + if (j == 5) + continue; + + algo_data->setsda(algo_data->data, 0); + msleep(15); + algo_data->setscl(algo_data->data, 0); + msleep(15); + algo_data->setsda(algo_data->data, 1); + msleep(15); + + /* Do the real work */ + edid = fb_do_probe_ddc_edid(adapter); + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + msleep(15); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 10; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + + algo_data->setsda(algo_data->data, 1); + msleep(15); + algo_data->setscl(algo_data->data, 0); + if (edid) + break; + } + /* Release the DDC lines when done or the Apple Cinema HD display + * will switch off + */ + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + + return edid; +} + +#define EDID_WIDTH 16 + +/** + * intel_ddc_get_modes - return a modelist based on EDID data from DDC + * @output: DRM output device to use + * + * Fetch the EDID information from @output using the DDC bus. + */ +struct drm_display_mode *intel_ddc_get_modes(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + u8 *edid; + int i; + + printk(KERN_ERR "fetching EDID data.\n"); + edid = fb_ddc_read(&intel_output->ddc_bus->adapter); + printk(KERN_ERR "done\n"); + + if (!edid) { + printk(KERN_ERR "no EDID data\n"); + return NULL; + } + + printk(KERN_ERR "EDID:\n" KERN_ERR); + for (i = 0; i < EDID_LENGTH; i++) { + if (i != 0 && ((i % 16) == 0)) + printk("\n" KERN_ERR); + printk("%02x", edid[i] & 0xff); + } + printk("\n"); + kfree(edid); + return NULL; +} diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/Makefile linux-2.6.21-rc4-modesetting/drivers/char/drm/Makefile --- linux-2.6.21-rc4/drivers/char/drm/Makefile 2007-03-15 17:20:01.000000000 -0700 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/Makefile 2007-03-22 16:41:42.000000000 -0700 @@ -6,14 +6,15 @@ drm-objs := drm_auth.o drm_bufs.o drm drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ - drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o + drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o drm_crtc.o tdfx-objs := tdfx_drv.o 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 i830-objs := i830_drv.o i830_dma.o i830_irq.o -i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o intel_lvds.o \ + intel_i2c.o intel_modes.o intel_crt.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_mm.o diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/Makefile linux-2.6.21-rc4-modesetting/Makefile --- linux-2.6.21-rc4/Makefile 2007-03-15 17:20:01.000000000 -0700 +++ linux-2.6.21-rc4-modesetting/Makefile 2007-03-21 11:01:38.000000000 -0700 @@ -1337,7 +1337,7 @@ quiet_cmd_cscope-file = FILELST cscope.f cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files quiet_cmd_cscope = MAKE cscope.out - cmd_cscope = cscope -b + cmd_cscope = cscope -bq cscope: FORCE $(call cmd,cscope-file)