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-18 14:21:49.000000000 -0700 @@ -0,0 +1,54 @@ +#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; +} + +void drm_output_destroy(struct drm_output *output) +{ + spin_lock(&drm_output_lock); + list_del(&output->head); + spin_unlock(&drm_output_lock); + kfree(output); +} + +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-18 14:22:42.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-16 16:25:55.000000000 -0700 @@ -767,6 +767,8 @@ void i915_driver_preclose(drm_device_t * } } +extern int i915_backlight(DRM_IOCTL_ARGS); + drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH}, @@ -784,6 +786,7 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_BACKLIGHT)] = {i915_backlight, DRM_AUTH}, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); 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-16 16:17:08.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-18 14:26:28.000000000 -0700 @@ -30,6 +30,9 @@ #ifndef _I915_DRV_H_ #define _I915_DRV_H_ +#include +#include + /* General customization: */ @@ -208,6 +211,15 @@ 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 SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 #define SR01 1 @@ -216,6 +228,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 +308,24 @@ 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) + #endif diff -Napur -X /home/jbarnes/dontdiff linux-2.6.21-rc4/drivers/char/drm/i915_lvds.c linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_lvds.c --- linux-2.6.21-rc4/drivers/char/drm/i915_lvds.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.21-rc4-modesetting/drivers/char/drm/i915_lvds.c 2007-03-18 14:33:43.000000000 -0700 @@ -0,0 +1,148 @@ +/* + * 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 i915_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; +} + +#if 0 +static int register_output(drm_device_t *dev, int type, char *name) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct i915_output *new_output; + int ret = 0; + + new_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!new_output) { + ret = -ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&new_output->head); + new_output->type = type; + switch (type) { + case INTEL_OUTPUT_ANALOG: + intel_register_i2c_bus(dev, &new_output->ddc_bus, GPIOA, name); + break; + case INTEL_OUTPUT_LVDS: + intel_register_i2c_bus(dev, &new_output->ddc_bus, GPIOC, name); + break; +#if 0 + case INTEL_OUTPUT_DVO: + intel_register_i2c_bus(dev, &new_output->ddc_bus, GPIOD, name); + intel_register_i2c_bus(dev, &new_output->i2c_bus, + dev_priv->dvo_chip == INTEL_DVO_CHIP_LVDS ? + GPIOB : GPIOE, name); + break; +#endif + case INTEL_OUTPUT_SDVO: + intel_register_i2c_bus(dev, &new_output->i2c_bus, GPIOE, name); + break; + default: + ret = -EINVAL; + goto out; + } + + spin_lock(&dev_priv->outputs_lock); + list_add(&new_output->head, &dev_priv->outputs); + spin_unlock(&dev_priv->outputs_lock); + return 0; + +out: + kfree(new_output); + return ret; +} +#endif + +struct drm_output_funcs i915_lvds_output_funcs; + +/** + * setup_outputs - create output structures and register i2c busses + * @dev: drm device + * + * All devices have at least one VGA connector, and some may have combinations + * of DVO, SDVO and/or LVDS to register too. + */ +static void setup_outputs(drm_device_t *dev) +{ + struct drm_output *output; + struct intel_output *i915_output; + struct drm_display_mode *modes; + + output = drm_output_create(dev, &i915_lvds_output_funcs, "LVDS"); + if (!output) + return; + + i915_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!i915_output) { + drm_output_destroy(output); + return; + } + + i915_output->type = INTEL_OUTPUT_LVDS; + output->driver_private = i915_output; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlace_allowed = 0; + output->doublescan_allowed = 0; + + intel_i2c_create(dev, i915_output, GPIOC, "LVDSDDC_C"); + modes = intel_ddc_get_modes(output); +} + 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-18 14:31:30.000000000 -0700 @@ -0,0 +1,54 @@ +#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; + u32 reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +struct intel_output { + int type; + struct intel_i2c_chan *i2c_bus; + struct intel_i2c_chan *ddc_bus; + bool load_detect_tmp; + void *dev_priv; +}; + +int intel_i2c_create(drm_device_t *dev, struct intel_output *output, + const u32 reg, const char *name); +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-18 14:35:00.000000000 -0700 @@ -0,0 +1,238 @@ +/* + * 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" + +/* bit locations in the registers */ +#define SCL_DIR_MASK 0x0001 +#define SCL_DIR 0x0002 +#define SCL_VAL_MASK 0x0004 +#define SCL_VAL_OUT 0x0008 +#define SCL_VAL_IN 0x0010 +#define SDA_DIR_MASK 0x0100 +#define SDA_DIR 0x0200 +#define SDA_VAL_MASK 0x0400 +#define SDA_VAL_OUT 0x0800 +#define SDA_VAL_IN 0x1000 + +static void setscl(void *data, int state) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + I915_WRITE(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | + SCL_DIR_MASK | SCL_VAL_MASK); + val = I915_READ(chan->reg); +} + +static void setsda(void *data, int state) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + I915_WRITE(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | + SDA_DIR_MASK | SDA_VAL_MASK); + val = I915_READ(chan->reg); +} + +static int getscl(void *data) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + I915_WRITE(chan->reg, SCL_DIR_MASK); + I915_WRITE(chan->reg, 0); + val = I915_READ(chan->reg); + return ((val & SCL_VAL_IN) != 0); +} + +static int getsda(void *data) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + I915_WRITE(chan->reg, SDA_DIR_MASK); + I915_WRITE(chan->reg, 0); + val = I915_READ(chan->reg); + return ((val & SDA_VAL_IN) != 0); +} + +int intel_i2c_create(drm_device_t *dev, struct intel_output *output, + const u32 reg, const char *name) +{ + struct intel_i2c_chan *chan; + int ret = 0; + + chan = kmalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); + if (!chan) { + ret = -ENOMEM; + goto out_err; + } + + 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 = &chan->drm_dev->pdev->dev; + chan->algo.setsda = setsda; + chan->algo.setscl = setscl; + chan->algo.getsda = getsda; + chan->algo.getscl = getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + setsda(chan, 1); + setscl(chan, 1); + udelay(20); + + ret = i2c_bit_add_bus(&chan->adapter); + if (ret) { + printk(KERN_ERR "Failed to register I2C bus %s.\n", name); + goto out_err; + } + + return ret; + +out_err: + kfree(chan); + return ret; +} + +static void delete_i2c_busses(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct i915_output *cur_output; + struct list_head *cur; +#if 0 + list_for_each(cur, &drm_outputs) { + cur_output = list_entry(cur, struct i915_output, head); + i2c_del_adapter(&cur_output->i2c_bus.adapter); + i2c_del_adapter(&cur_output->ddc_bus.adapter); + } +#endif +} + +#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; +} + +struct drm_display_mode *intel_ddc_get_modes(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + char *edid = fb_ddc_read(&intel_output->ddc_bus->adapter); + return (struct drm_display_mode *)edid; +} + + 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-18 13:32:19.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 i915_lvds.o \ + intel_i2c.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/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:15:29.000000000 -0700 @@ -0,0 +1,79 @@ +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 \ No newline at end of file