diff options
| -rw-r--r-- | linux-core/drmP.h | 4 | ||||
| -rw-r--r-- | linux-core/drm_compat.h | 9 | ||||
| -rw-r--r-- | linux-core/drm_crtc.c | 95 | ||||
| -rw-r--r-- | linux-core/drm_crtc.h | 38 | ||||
| -rw-r--r-- | linux-core/drm_edid.c | 28 | ||||
| -rw-r--r-- | linux-core/drm_sysfs.c | 199 | ||||
| -rw-r--r-- | linux-core/intel_crt.c | 2 | ||||
| -rw-r--r-- | linux-core/intel_display.c | 148 | ||||
| -rw-r--r-- | linux-core/intel_drv.h | 7 | ||||
| -rw-r--r-- | linux-core/intel_lvds.c | 28 | ||||
| -rw-r--r-- | linux-core/intel_sdvo.c | 35 | ||||
| -rw-r--r-- | linux-core/intel_tv.c | 277 | ||||
| -rw-r--r-- | shared-core/i915_drv.h | 3 | ||||
| -rw-r--r-- | shared-core/i915_init.c | 1 | ||||
| -rw-r--r-- | shared-core/i915_irq.c | 60 | 
15 files changed, 635 insertions, 299 deletions
| diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f96e6bee..24f8c3d8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1311,7 +1311,11 @@ struct drm_sysfs_class;  extern struct class *drm_sysfs_create(struct module *owner, char *name);  extern void drm_sysfs_destroy(void);  extern int drm_sysfs_device_add(struct drm_minor *minor); +extern void drm_sysfs_hotplug_event(struct drm_device *dev);  extern void drm_sysfs_device_remove(struct drm_minor *minor); +extern char *drm_get_output_status_name(enum drm_output_status status); +extern int drm_sysfs_output_add(struct drm_output *output); +extern void drm_sysfs_output_remove(struct drm_output *output);  /*   * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 03838a18..046c7122 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -339,6 +339,15 @@ extern unsigned long round_jiffies_relative(unsigned long j);  extern struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn);  #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +static inline int kobject_uevent_env(struct kobject *kobj, +                                     enum kobject_action action, +                                     char *envp[]) +{ +    return 0; +} +#endif +  #ifndef PM_EVENT_PRETHAW   #define PM_EVENT_PRETHAW 3  #endif diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 0cd0ebd0..1e5195db 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -47,6 +47,18 @@ static struct drm_prop_enum_list drm_dpms_enum_list[] =    { DPMSModeSuspend, "Suspend" },    { DPMSModeOff, "Off" }  }; + +char *drm_get_dpms_name(int val) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) +		if (drm_dpms_enum_list[i].type == val) +			return drm_dpms_enum_list[i].name; + +	return "unknown"; +} +  static struct drm_prop_enum_list drm_conn_enum_list[] =   { { ConnectorUnknown, "Unknown" },    { ConnectorVGA, "VGA" }, @@ -79,6 +91,16 @@ char *drm_get_output_name(struct drm_output *output)  	return buf;  } +char *drm_get_output_status_name(enum drm_output_status status) +{ +	if (status == output_status_connected) +		return "connected"; +	else if (status == output_status_disconnected) +		return "disconnected"; +	else +		return "unknown"; +} +  /**   * drm_idr_get - allocate a new identifier   * @dev: DRM device @@ -418,7 +440,6 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,  	struct drm_device *dev = crtc->dev;  	struct drm_display_mode *adjusted_mode, saved_mode;  	int saved_x, saved_y; -	bool didLock = false;  	struct drm_output *output;  	bool ret = true; @@ -429,8 +450,6 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,  	if (!crtc->enabled)  		return true; -	didLock = crtc->funcs->lock(crtc); -  	saved_mode = crtc->mode;  	saved_x = crtc->x;  	saved_y = crtc->y; @@ -522,9 +541,6 @@ done:  		crtc->x = saved_x;  		crtc->y = saved_y;  	}  - -	if (didLock) -		crtc->funcs->unlock (crtc);  	return ret;  } @@ -621,7 +637,6 @@ struct drm_output *drm_output_create(struct drm_device *dev,  	output->id = drm_idr_get(dev, output);  	output->output_type = output_type;  	output->output_type_id = 1; /* TODO */ -	output->subpixel_order = SubPixelUnknown;  	INIT_LIST_HEAD(&output->user_modes);  	INIT_LIST_HEAD(&output->probed_modes);  	INIT_LIST_HEAD(&output->modes); @@ -752,9 +767,25 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev)  	dev->mode_config.connector_num_property->values[0] = 0;  	dev->mode_config.connector_num_property->values[1] = 20; -	/* -	 * TV specific properties -	 */ +	return 0; +} + +/** + * drm_create_tv_properties - create TV specific output properties + * @dev: DRM device + * @num_modes: number of different TV formats (modes) supported + * @modes: array of pointers to strings containing name of each format + * + * Called by a driver's TV initialization routine, this function creates + * the TV specific output properties for a given device.  Caller is + * responsible for allocating a list of format names and passing them to + * this routine. + */ +bool drm_create_tv_properties(struct drm_device *dev, int num_modes, +			      char *modes[]) +{ +	int i; +  	dev->mode_config.tv_left_margin_property =  		drm_property_create(dev, DRM_MODE_PROP_RANGE |  				    DRM_MODE_PROP_IMMUTABLE, @@ -763,28 +794,33 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev)  	dev->mode_config.tv_left_margin_property->values[1] = 100;  	dev->mode_config.tv_right_margin_property = -		drm_property_create(dev, DRM_MODE_PROP_RANGE | -				    DRM_MODE_PROP_IMMUTABLE, +		drm_property_create(dev, DRM_MODE_PROP_RANGE,  				    "right margin", 2);  	dev->mode_config.tv_right_margin_property->values[0] = 0;  	dev->mode_config.tv_right_margin_property->values[1] = 100;  	dev->mode_config.tv_top_margin_property = -		drm_property_create(dev, DRM_MODE_PROP_RANGE | -				    DRM_MODE_PROP_IMMUTABLE, +		drm_property_create(dev, DRM_MODE_PROP_RANGE,  				    "top margin", 2);  	dev->mode_config.tv_top_margin_property->values[0] = 0;  	dev->mode_config.tv_top_margin_property->values[1] = 100;  	dev->mode_config.tv_bottom_margin_property = -		drm_property_create(dev, DRM_MODE_PROP_RANGE | -				    DRM_MODE_PROP_IMMUTABLE, +		drm_property_create(dev, DRM_MODE_PROP_RANGE,  				    "bottom margin", 2);  	dev->mode_config.tv_bottom_margin_property->values[0] = 0;  	dev->mode_config.tv_bottom_margin_property->values[1] = 100; +	dev->mode_config.tv_mode_property = +		drm_property_create(dev, DRM_MODE_PROP_ENUM, +				    "mode", num_modes); +	for (i = 0; i < num_modes; i++) +		drm_property_add_enum(dev->mode_config.tv_mode_property, i, +				      i, modes[i]); +  	return 0;  } +EXPORT_SYMBOL(drm_create_tv_properties);  /**   * drm_mode_config_init - initialize DRM mode_configuration structure @@ -1054,6 +1090,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)  	struct drm_property *property, *pt;  	list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { +		drm_sysfs_output_remove(output);  		drm_output_destroy(output);  	} @@ -1226,6 +1263,8 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output,  			DRM_ERROR("failed to set mode after hotplug\n");  	} +	drm_sysfs_hotplug_event(dev); +  	drm_disable_unused_functions(dev);  	return 0; @@ -1530,9 +1569,9 @@ int drm_mode_getoutput(struct drm_device *dev,  	out_resp->output_type = output->output_type;  	out_resp->output_type_id = output->output_type_id; -	out_resp->mm_width = output->mm_width; -	out_resp->mm_height = output->mm_height; -	out_resp->subpixel = output->subpixel_order; +	out_resp->mm_width = output->display_info.width_mm; +	out_resp->mm_height = output->display_info.height_mm; +	out_resp->subpixel = output->display_info.subpixel_order;  	out_resp->connection = output->status;  	if (output->crtc)  		out_resp->crtc = output->crtc->id; @@ -2223,6 +2262,24 @@ int drm_output_property_set_value(struct drm_output *output,  }  EXPORT_SYMBOL(drm_output_property_set_value); +int drm_output_property_get_value(struct drm_output *output, +				  struct drm_property *property, uint64_t *val) +{ +	int i; + +	for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { +		if (output->property_ids[i] == property->id) { +			*val = output->property_values[i]; +			break; +		} +	} + +	if (i == DRM_OUTPUT_MAX_PROPERTY) +		return -EINVAL; +	return 0; +} +EXPORT_SYMBOL(drm_output_property_get_value); +  int drm_mode_getproperty_ioctl(struct drm_device *dev,  			       void *data, struct drm_file *file_priv)  { diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index bbeab603..20b1ea06 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -199,7 +199,7 @@ struct drm_display_info {  	bool gtf_supported;  	bool standard_color;  	enum { -		monochrome, +		monochrome = 0,  		rgb,  		other,  		unknown, @@ -225,6 +225,8 @@ struct drm_display_info {  	unsigned int wpx2, wpy2;  	unsigned int wpgamma2; +	enum subpixel_order subpixel_order; +  	/* Preferred mode (if any) */  	struct drm_display_mode *preferred_mode;  	char *raw_edid; /* if any */ @@ -306,13 +308,10 @@ struct drm_crtc_funcs {  	 */  	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);  	void (*prepare)(struct drm_crtc *crtc);  	void (*commit)(struct drm_crtc *crtc); @@ -365,10 +364,6 @@ struct drm_crtc {  	bool enabled; -	/* JJJ: are these needed? */ -	bool cursor_in_range; -	bool cursor_shown; -  	struct drm_display_mode mode;  	int x, y; @@ -376,8 +371,6 @@ struct drm_crtc {  	int desired_x, desired_y;  	const struct drm_crtc_funcs *funcs;  	void *driver_private; - -	/* RRCrtcPtr randr_crtc? */  };  extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, @@ -418,7 +411,6 @@ struct drm_output_funcs {  			 struct drm_display_mode *adjusted_mode);  	enum drm_output_status (*detect)(struct drm_output *output);  	int (*get_modes)(struct drm_output *output); -	/* JJJ: type checking for properties via property value type */  	bool (*set_property)(struct drm_output *output, struct drm_property *property,  			     uint64_t val);  	void (*cleanup)(struct drm_output *output); @@ -438,9 +430,6 @@ struct drm_output_funcs {   * @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   * @funcs: output control functions   * @driver_private: private driver data   * @@ -451,6 +440,8 @@ struct drm_output_funcs {   */  struct drm_output {  	struct drm_device *dev; +	struct device kdev; +	struct device_attribute *attr;  	struct list_head head;  	struct drm_crtc *crtc;  	int id; /* idr assigned */ @@ -463,20 +454,13 @@ struct drm_output {  	bool doublescan_allowed;  	struct list_head modes; /* list of modes on this output */ -	/* -	  OptionInfoPtr options; -	  XF86ConfMonitorPtr conf_monitor; -	 */  	int initial_x, initial_y;  	enum drm_output_status status;  	/* these are modes added by probing with DDC or the BIOS */  	struct list_head probed_modes; -	/* xf86MonPtr MonInfo; */ -	enum subpixel_order subpixel_order; -	int mm_width, mm_height; -	struct drm_display_info *monitor_info; /* if any */ +	struct drm_display_info display_info;    	const struct drm_output_funcs *funcs;  	void *driver_private; @@ -527,7 +511,6 @@ struct drm_mode_config {  	int num_output;  	struct list_head output_list; -	/* int compat_output? */  	int num_crtc;  	struct list_head crtc_list; @@ -535,8 +518,6 @@ struct drm_mode_config {  	int min_width, min_height;  	int max_width, max_height; -	/* DamagePtr rotationDamage? */ -	/* DGA stuff? */  	struct drm_mode_config_funcs *funcs;  	unsigned long fb_base; @@ -563,6 +544,7 @@ struct drm_output *drm_output_create(struct drm_device *dev,  				     int type);  extern char *drm_get_output_name(struct drm_output *output); +extern char *drm_get_dpms_name(int val);  extern void drm_output_destroy(struct drm_output *output);  extern void drm_fb_release(struct file *filp); @@ -606,6 +588,9 @@ extern int drm_mode_output_update_edid_property(struct drm_output *output,  extern int drm_output_property_set_value(struct drm_output *output,  					 struct drm_property *property,  					 uint64_t value); +extern int drm_output_property_get_value(struct drm_output *output, +					 struct drm_property *property, +					 uint64_t *value);  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, @@ -616,6 +601,7 @@ extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);  extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);  extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,  		       int x, int y); +extern bool drm_crtc_in_use(struct drm_crtc *crtc);  extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected);  extern int drm_output_attach_property(struct drm_output *output, @@ -625,6 +611,8 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag  extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);  extern int drm_property_add_enum(struct drm_property *property, int index,   				 uint64_t value, const char *name); +extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, +				     char *formats[]);  /* IOCTLs */  extern int drm_mode_getresources(struct drm_device *dev, diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 9762567b..e033abdf 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -291,7 +291,11 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid)  				if (i == 0 && edid->preferred_timing)  					newmode->type |= DRM_MODE_TYPE_PREFERRED;  				drm_mode_probed_add(output, newmode); -				      + +				/* Use first one for output's preferred mode */ +				if (!output->display_info.preferred_mode) +					output->display_info.preferred_mode = +						newmode;  				modes++;  			}  			continue; @@ -460,6 +464,9 @@ struct edid *drm_get_edid(struct drm_output *output,  		kfree(edid);  		return NULL;  	} + +	output->display_info.raw_edid = (char *)edid; +  	return edid;  }  EXPORT_SYMBOL(drm_get_edid); @@ -488,6 +495,25 @@ int drm_add_edid_modes(struct drm_output *output, struct edid *edid)  	num_modes += add_established_modes(output, edid);  	num_modes += add_standard_modes(output, edid);  	num_modes += add_detailed_info(output, edid); + +	output->display_info.serration_vsync = edid->serration_vsync; +	output->display_info.sync_on_green = edid->sync_on_green; +	output->display_info.composite_sync = edid->composite_sync; +	output->display_info.separate_syncs = edid->separate_syncs; +	output->display_info.blank_to_black = edid->blank_to_black; +	output->display_info.video_level = edid->video_level; +	output->display_info.digital = edid->digital; +	output->display_info.width_mm = edid->width_cm * 10; +	output->display_info.height_mm = edid->height_cm * 10; +	output->display_info.gamma = edid->gamma; +	output->display_info.gtf_supported = edid->default_gtf; +	output->display_info.standard_color = edid->standard_color; +	output->display_info.display_type = edid->display_type; +	output->display_info.active_off_supported = edid->pm_active_off; +	output->display_info.suspend_supported = edid->pm_suspend; +	output->display_info.standby_supported = edid->pm_standby; +	output->display_info.gamma = edid->gamma; +  	return num_modes;  }  EXPORT_SYMBOL(drm_add_edid_modes); diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3372a713..ef73cc83 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -133,10 +133,6 @@ static ssize_t show_dri(struct device *device, struct device_attribute *attr,  	return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);  } -static struct device_attribute device_attrs[] = { -	__ATTR(dri_library_name, S_IRUGO, show_dri, NULL), -}; -  /**   * drm_sysfs_device_release - do nothing   * @dev: Linux device @@ -150,6 +146,191 @@ static void drm_sysfs_device_release(struct device *dev)  	return;  } +/* + * Output properties + */ +static ssize_t status_show(struct device *device, +			   struct device_attribute *attr, +			   char *buf) +{ +	struct drm_output *output = container_of(device, struct drm_output, kdev); +	return snprintf(buf, PAGE_SIZE, "%s", +			drm_get_output_status_name(output->funcs->detect(output))); +} + +static ssize_t dpms_show(struct device *device, +			   struct device_attribute *attr, +			   char *buf) +{ +	struct drm_output *output = container_of(device, struct drm_output, kdev); +	struct drm_device *dev = output->dev; +	uint64_t dpms_status; +	int ret; + +	ret = drm_output_property_get_value(output, +					    dev->mode_config.dpms_property, +					    &dpms_status); +	if (ret) +		return 0; +	 +	return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); +} + +static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, +			 char *buf, loff_t off, size_t count) +{ +	struct device *output_dev = container_of(kobj, struct device, kobj); +	struct drm_output *output = container_of(output_dev, struct drm_output, +						 kdev); +	unsigned char *edid; +	size_t size; + +	if (!output->edid_blob_ptr) +		return 0; + +	edid = output->edid_blob_ptr->data; +	size = output->edid_blob_ptr->length; +	if (!edid) +		return 0; +		 +	if (off >= size) +		return 0; + +	if (off + count > size) +		count = size - off; +	memcpy(buf, edid + off, count); + +	return count; +} + +static ssize_t modes_show(struct device *device, +			   struct device_attribute *attr, +			   char *buf) +{ +	struct drm_output *output = container_of(device, struct drm_output, kdev); +	struct drm_display_mode *mode; +	int written = 0; + +	list_for_each_entry(mode, &output->modes, head) { +		written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", +				    mode->name); +	} + +	return written; +} + +static struct device_attribute output_attrs[] = { +	__ATTR_RO(status), +	__ATTR_RO(dpms), +	__ATTR_RO(modes), +}; + +static struct bin_attribute edid_attr = { +	.attr.name = "edid", +	.size = 128, +	.read = edid_show, +}; + +/** + * drm_sysfs_output_add - add an output to sysfs + * @output: output to add + * + * Create an output device in sysfs, along with its associated output + * properties (so far, connection status, dpms, mode list & edid) and + * generate a hotplug event so userspace knows there's a new output + * available. + */ +int drm_sysfs_output_add(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	int ret = 0, i, j; + +	if (device_is_registered(&output->kdev)) +	    return 0; + +	output->kdev.parent = &dev->primary->kdev; +	output->kdev.class = drm_class; +	output->kdev.release = drm_sysfs_device_release; + +	DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_output_name(output)); + +	snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", +		 dev->primary->index, drm_get_output_name(output)); +	ret = device_register(&output->kdev); + +	if (ret) { +		DRM_ERROR("failed to register output device: %d\n", ret); +		goto out; +	} + +	for (i = 0; i < ARRAY_SIZE(output_attrs); i++) { +		ret = device_create_file(&output->kdev, &output_attrs[i]); +		if (ret) +			goto err_out_files; +	} + +	ret = sysfs_create_bin_file(&output->kdev.kobj, &edid_attr); +	if (ret) +		goto err_out_files; + +	/* Let userspace know we have a new output */ +	drm_sysfs_hotplug_event(dev); + +	return 0; + +err_out_files: +	if (i > 0) +		for (j = 0; j < i; j++) +			device_remove_file(&output->kdev, &output_attrs[i]); +	device_unregister(&output->kdev); + +out: +	return ret; +} +EXPORT_SYMBOL(drm_sysfs_output_add); + +/** + * drm_sysfs_output_remove - remove an output device from sysfs + * @output: output to remove + * + * Remove @output and its associated attributes from sysfs.  Note that + * the device model core will take care of sending the "remove" uevent + * at this time, so we don't need to do it. + */ +void drm_sysfs_output_remove(struct drm_output *output) +{ +	int i; + +	DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); +	for (i = 0; i < i; i++) +		device_remove_file(&output->kdev, &output_attrs[i]); +	sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); +	device_unregister(&output->kdev); +} +EXPORT_SYMBOL(drm_sysfs_output_remove); + +/** + * drm_sysfs_hotplug_event - generate a DRM uevent + * @dev: DRM device + * + * Send a uevent for the DRM device specified by @dev.  Currently we only + * set HOTPLUG=1 in the uevent environment, but this could be expanded to + * deal with other types of events. + */ +void drm_sysfs_hotplug_event(struct drm_device *dev) +{ +	char *event_string = "HOTPLUG=1"; +	char *envp[] = { event_string, NULL }; + +	DRM_DEBUG("generating hotplug event\n"); + +	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); +} + +static struct device_attribute dri_attrs[] = { +	__ATTR(dri_library_name, S_IRUGO, show_dri, NULL), +}; +  /**   * drm_sysfs_device_add - adds a class device to sysfs for a character driver   * @dev: DRM device to be added @@ -184,8 +365,8 @@ int drm_sysfs_device_add(struct drm_minor *minor)  		goto err_out;  	} -	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { -		err = device_create_file(&minor->kdev, &device_attrs[i]); +	for (i = 0; i < ARRAY_SIZE(dri_attrs); i++) { +		err = device_create_file(&minor->kdev, &dri_attrs[i]);  		if (err)  			goto err_out_files;  	} @@ -195,7 +376,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)  err_out_files:  	if (i > 0)  		for (j = 0; j < i; j++) -			device_remove_file(&minor->kdev, &device_attrs[i]); +			device_remove_file(&minor->kdev, &dri_attrs[i]);  	device_unregister(&minor->kdev);  err_out: @@ -213,7 +394,7 @@ void drm_sysfs_device_remove(struct drm_minor *minor)  {  	int i; -	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) -		device_remove_file(&minor->kdev, &device_attrs[i]); +	for (i = 0; i < ARRAY_SIZE(dri_attrs); i++) +		device_remove_file(&minor->kdev, &dri_attrs[i]);  	device_unregister(&minor->kdev);  } diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 915e430d..ef40871e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -261,5 +261,7 @@ void intel_crt_init(struct drm_device *dev)  	output->interlace_allowed = 0;  	output->doublescan_allowed = 0; +	drm_sysfs_output_add(output); +  	drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA);  } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index fa2b9bea..6aa61256 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -567,25 +567,8 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)  		DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);  		break;  	} -} - -static bool intel_crtc_lock(struct drm_crtc *crtc) -{ -   /* Sync the engine before mode switch */ -//   i830WaitSync(crtc->scrn); -#if 0 // TODO def XF86DRI -    return I830DRILock(crtc->scrn); -#else -    return FALSE; -#endif -} - -static void intel_crtc_unlock (struct drm_crtc *crtc) -{ -#if 0 // TODO def XF86DRI -    I830DRIUnlock (crtc->scrn); -#endif +	intel_crtc->dpms_mode = mode;  }  static void intel_crtc_prepare (struct drm_crtc *crtc) @@ -1097,6 +1080,129 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,  	intel_crtc->lut_b[regno] = blue >> 8;  } +/** + * Get a pipe with a simple mode set on it for doing load-based monitor + * detection. + * + * It will be up to the load-detect code to adjust the pipe as appropriate for + * its requirements.  The pipe will be connected to no other outputs. + * + * Currently this code will only succeed if there is a pipe with no outputs + * configured for it.  In the future, it could choose to temporarily disable + * some outputs to free up a pipe for its use. + * + * \return crtc, or NULL if no pipes are available. + */ +     +/* VESA 640x480x72Hz mode to set on the pipe */ +static struct drm_display_mode load_detect_mode = { +	DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, +		 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), +}; + +struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, +					    struct drm_display_mode *mode, +					    int *dpms_mode) +{ +	struct drm_device *dev = output->dev; +	struct intel_output *intel_output = output->driver_private; +	struct intel_crtc *intel_crtc; +	struct drm_crtc *possible_crtc; +	struct drm_crtc *supported_crtc =NULL; +	struct drm_crtc *crtc = NULL; +	int i = -1; + +	/* +	 * Algorithm gets a little messy: +	 *   - if the output already has an assigned crtc, use it (but make +	 *     sure it's on first) +	 *   - try to find the first unused crtc that can drive this output, +	 *     and use that if we find one +	 *   - if there are no unused crtcs available, try to use the first +	 *     one we found that supports the output +	 */ + +	/* See if we already have a CRTC for this output */ +	if (output->crtc) { +		crtc = output->crtc; +		/* Make sure the crtc and output are running */ +		intel_crtc = crtc->driver_private; +		*dpms_mode = intel_crtc->dpms_mode; +		if (intel_crtc->dpms_mode != DPMSModeOn) { +			crtc->funcs->dpms(crtc, DPMSModeOn); +			output->funcs->dpms(output, DPMSModeOn); +		} +		return crtc; +	} + +	/* Find an unused one (if possible) */ +	list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { +		i++; +		if (!(output->possible_crtcs & (1 << i))) +			continue; +		if (!possible_crtc->enabled) { +			crtc = possible_crtc; +			break; +		} +		if (!supported_crtc) +			supported_crtc = possible_crtc; +	} + +	/* +	 * If we didn't find an unused CRTC, use the first available one +	 * that can drive this output. +	 */ +	if (!crtc) { +		crtc = supported_crtc; +		if (!crtc) +			return NULL; +	} + +	output->crtc = crtc; +	intel_output->load_detect_temp = TRUE; +     +	intel_crtc = crtc->driver_private; +	*dpms_mode = intel_crtc->dpms_mode; + +	if (!crtc->enabled) { +		if (!mode) +			mode = &load_detect_mode; +		drm_crtc_set_mode(crtc, mode, 0, 0); +	} else { +		if (intel_crtc->dpms_mode != DPMSModeOn) +			crtc->funcs->dpms(crtc, DPMSModeOn); + +		/* Add this output to the crtc */ +		output->funcs->mode_set(output, &crtc->mode, &crtc->mode); +		output->funcs->commit(output); +	} +	/* let the output get through one full cycle before testing */ +	intel_wait_for_vblank(dev); + +	return crtc; +} + +void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) +{ +	struct drm_device *dev = output->dev; +	struct intel_output *intel_output = output->driver_private; +	struct drm_crtc *crtc = output->crtc; +     +	if (intel_output->load_detect_temp) { +		output->crtc = NULL; +		intel_output->load_detect_temp = FALSE; +		crtc->enabled = drm_crtc_in_use(crtc); +		drm_disable_unused_functions(dev); +	} + +	/* Switch crtc and output back off if necessary */ +	if (crtc->enabled && dpms_mode != DPMSModeOn) { +		if (output->crtc == crtc) +			output->funcs->dpms(output, dpms_mode); +		crtc->funcs->dpms(crtc, dpms_mode); +	} +} +  /* 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)  { @@ -1209,8 +1315,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,  static const struct drm_crtc_funcs intel_crtc_funcs = {  	.dpms = intel_crtc_dpms, -	.lock = intel_crtc_lock, -	.unlock = intel_crtc_unlock,  	.mode_fixup = intel_crtc_mode_fixup,  	.mode_set = intel_crtc_mode_set,  	.mode_set_base = intel_pipe_set_base, @@ -1246,6 +1350,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe)  	}  	intel_crtc->cursor_addr = 0; +	intel_crtc->dpms_mode = DPMSModeOff;  	crtc->driver_private = intel_crtc;  } @@ -1293,6 +1398,9 @@ static void intel_setup_outputs(struct drm_device *dev)  		intel_sdvo_init(dev, SDVOC);  	} +	if (IS_I9XX(dev) && !IS_I915G(dev)) +		intel_tv_init(dev); +  	list_for_each_entry(output, &dev->mode_config.output_list, head) {  		struct intel_output *intel_output = output->driver_private;  		int crtc_mask = 0, clone_mask = 0; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index a36fd3f1..51c52c84 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -58,6 +58,7 @@ struct intel_crtc {  	int plane;  	uint32_t cursor_addr;  	u8 lut_r[256], lut_g[256], lut_b[256]; +	int dpms_mode;  };  struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, @@ -68,6 +69,7 @@ extern bool intel_ddc_probe(struct drm_output *output);  extern void intel_crt_init(struct drm_device *dev);  extern void intel_sdvo_init(struct drm_device *dev, int output_device); +extern void intel_tv_init(struct drm_device *dev);  extern void intel_lvds_init(struct drm_device *dev);  extern void intel_crtc_load_lut(struct drm_crtc *crtc); @@ -77,6 +79,11 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,   						    struct drm_crtc *crtc);  extern void intel_wait_for_vblank(struct drm_device *dev);  extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); +extern struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, +						   struct drm_display_mode *mode, +						   int *dpms_mode); +extern void intel_release_load_detect_pipe(struct drm_output *output, +					   int dpms_mode);  extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB);  extern int intel_sdvo_supports_hotplug(struct drm_output *output); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 80f77af6..92a1d600 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -298,24 +298,15 @@ static int intel_lvds_get_modes(struct drm_output *output)  	if (ret)  		return ret; -	/* Didn't get an EDID */ -	if (!output->monitor_info) { -		struct drm_display_info *dspinfo; -		dspinfo = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); -		if (!dspinfo) -			goto out; - -		/* Set wide sync ranges so we get all modes -		 * handed to valid_mode for checking -		 */ -		dspinfo->min_vfreq = 0; -		dspinfo->max_vfreq = 200; -		dspinfo->min_hfreq = 0; -		dspinfo->max_hfreq = 200; -		output->monitor_info = dspinfo; -	} +	/* Didn't get an EDID, so +	 * Set wide sync ranges so we get all modes +	 * handed to valid_mode for checking +	 */ +	output->display_info.min_vfreq = 0; +	output->display_info.max_vfreq = 200; +	output->display_info.min_hfreq = 0; +	output->display_info.max_hfreq = 200; -out:  	if (dev_priv->panel_fixed_mode != NULL) {  		struct drm_display_mode *mode =  			drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); @@ -385,7 +376,7 @@ void intel_lvds_init(struct drm_device *dev)  	intel_output->type = INTEL_OUTPUT_LVDS;  	output->driver_private = intel_output; -	output->subpixel_order = SubPixelHorizontalRGB; +	output->display_info.subpixel_order = SubPixelHorizontalRGB;  	output->interlace_allowed = FALSE;  	output->doublescan_allowed = FALSE; @@ -500,6 +491,7 @@ void intel_lvds_init(struct drm_device *dev)  #endif  out: +	drm_sysfs_output_add(output);  	drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorLVDS);  	return; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index a8441d8f..ba6fe9a8 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -126,14 +126,6 @@ static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr,  	return false;  } - -static bool intel_sdvo_read_byte_quiet(struct drm_output *output, int addr, -				       u8 *ch) -{ -	return true; - -} -  static bool intel_sdvo_write_byte(struct drm_output *output, int addr,  				  u8 ch)  { @@ -863,23 +855,6 @@ static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_  	return true;  } - -static void intel_sdvo_dump_cmd(struct drm_output *output, int opcode) -{ - - -} - -static void intel_sdvo_dump_device(struct drm_output *output) -{ - -} - -void intel_sdvo_dump(void) -{ - -} -  struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB)  {  	struct drm_output *output = 0; @@ -1083,28 +1058,28 @@ void intel_sdvo_init(struct drm_device *dev, int output_device)  	if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)  	{  		sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; -		output->subpixel_order = SubPixelHorizontalRGB; +		output->display_info.subpixel_order = SubPixelHorizontalRGB;  		output_type = DRM_MODE_OUTPUT_DAC;  		connector_type = ConnectorVGA;  	}  	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)  	{  		sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; -		output->subpixel_order = SubPixelHorizontalRGB; +		output->display_info.subpixel_order = SubPixelHorizontalRGB;  		output_type = DRM_MODE_OUTPUT_DAC;  		connector_type = ConnectorVGA;  	}  	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)  	{  		sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; -		output->subpixel_order = SubPixelHorizontalRGB; +		output->display_info.subpixel_order = SubPixelHorizontalRGB;  		output_type = DRM_MODE_OUTPUT_TMDS;  		connector_type = ConnectorDVID;  	}  	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)  	{  		sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; -		output->subpixel_order = SubPixelHorizontalRGB; +		output->display_info.subpixel_order = SubPixelHorizontalRGB;  		output_type = DRM_MODE_OUTPUT_TMDS;  		connector_type = ConnectorDVID;  	} @@ -1123,6 +1098,8 @@ void intel_sdvo_init(struct drm_device *dev, int output_device)  	output->output_type = output_type;  	output->output_type_id = output_id; +	drm_sysfs_output_add(output); +  	/* Set the input timing to the screen. Assume always input 0. */  	intel_sdvo_set_target_input(output, true, false); diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 0edbdbac..89bdda1c 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -37,14 +37,6 @@  #include "i915_drm.h"  #include "i915_drv.h" -enum tv_type { -	TV_TYPE_NONE, -	TV_TYPE_UNKNOWN, -	TV_TYPE_COMPOSITE, -	TV_TYPE_SVIDEO, -	TV_TYPE_COMPONENT -}; -  enum tv_margin {  	TV_MARGIN_LEFT, TV_MARGIN_TOP,  	TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM @@ -1145,14 +1137,14 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,  	switch (tv_priv->type) {  	default: -	case TV_TYPE_UNKNOWN: -	case TV_TYPE_COMPOSITE: +	case ConnectorUnknown: +	case ConnectorComposite:  		tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;  		video_levels = tv_mode->composite_levels;  		color_conversion = tv_mode->composite_color;  		burst_ena = tv_mode->burst_ena;  		break; -	case TV_TYPE_COMPONENT: +	case ConnectorComponent:  		tv_ctl |= TV_ENC_OUTPUT_COMPONENT;  		video_levels = &component_levels;  		if (tv_mode->burst_ena) @@ -1161,7 +1153,7 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,  			color_conversion = &hdtv_csc_yprpb;  		burst_ena = FALSE;  		break; -	case TV_TYPE_SVIDEO: +	case ConnectorSVIDEO:  		tv_ctl |= TV_ENC_OUTPUT_SVIDEO;  		video_levels = tv_mode->svideo_levels;  		color_conversion = tv_mode->svideo_color; @@ -1218,8 +1210,11 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,  	if (tv_mode->pal_burst)  		tv_ctl |= TV_PAL_BURST;  	scctl1 = 0; -	if (tv_mode->dda1_inc) +	/* dda1 implies valid video levels */ +	if (tv_mode->dda1_inc) {  		scctl1 |= TV_SC_DDA1_EN; +		scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; +	}  	if (tv_mode->dda2_inc)  		scctl1 |= TV_SC_DDA2_EN; @@ -1228,7 +1223,6 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,  		scctl1 |= TV_SC_DDA3_EN;  	scctl1 |= tv_mode->sc_reset; -	scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;  	scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;  	scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | @@ -1255,22 +1249,26 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,  	I915_WRITE(TV_SC_CTL_2, scctl2);  	I915_WRITE(TV_SC_CTL_3, scctl3); -	I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | -		   color_conversion->gy); -	I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | -		   color_conversion->ay); -	I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | -		   color_conversion->gu); -	I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | -		   color_conversion->au); -	I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | -		   color_conversion->gv); -	I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | -		   color_conversion->av); +	if (color_conversion) { +		I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | +			   color_conversion->gy); +		I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | +			   color_conversion->ay); +		I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | +			   color_conversion->gu); +		I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | +			   color_conversion->au); +		I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | +			   color_conversion->gv); +		I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | +			   color_conversion->av); +	}  	I915_WRITE(TV_CLR_KNOBS, 0x00606000); -	I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | -			      (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); +	if (video_levels) +		I915_WRITE(TV_CLR_LEVEL, +			   ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | +			    (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));  	{  		int pipeconf_reg = (intel_crtc->pipe == 0) ?  			PIPEACONF : PIPEBCONF; @@ -1364,7 +1362,7 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)  	struct intel_output *intel_output = output->driver_private;  	u32 tv_ctl, save_tv_ctl;  	u32 tv_dac, save_tv_dac; -	int type = TV_TYPE_UNKNOWN; +	int type = ConnectorUnknown;  	tv_dac = I915_READ(TV_DAC);  	/* @@ -1402,24 +1400,21 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)  	 */  	if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {  		DRM_DEBUG("Detected Composite TV connection\n"); -		type = TV_TYPE_COMPOSITE; +		type = ConnectorComposite;  	} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {  		DRM_DEBUG("Detected S-Video TV connection\n"); -		type = TV_TYPE_SVIDEO; +		type = ConnectorSVIDEO;  	} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {  		DRM_DEBUG("Detected Component TV connection\n"); -		type = TV_TYPE_COMPONENT; +		type = ConnectorComponent;  	} else {  		DRM_DEBUG("No TV connection detected\n"); -		type = TV_TYPE_NONE; +		type = -1;  	}  	return type;  } -static int -intel_tv_format_configure_property (struct drm_output *output); -  /**   * Detect the TV connection.   * @@ -1438,27 +1433,26 @@ intel_tv_detect(struct drm_output *output)  	mode = reported_modes[0];  	drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); -#if 0 -	/* FIXME: pipe allocation for load detection */ -	crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode); + +	crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode);  	if (crtc) {  		type = intel_tv_detect_type(crtc, output); -		i830ReleaseLoadDetectPipe (output, dpms_mode); +		intel_release_load_detect_pipe(output, dpms_mode);  	} -#endif +  	if (type != tv_priv->type) { +		struct drm_property *connector_property = +			output->dev->mode_config.connector_type_property; +  		tv_priv->type = type; -		intel_tv_format_configure_property (output); +		drm_output_property_set_value(output, connector_property, +					      type);  	} -	switch (type) { -	case TV_TYPE_NONE: +	if (type < 0)  		return output_status_disconnected; -	case TV_TYPE_UNKNOWN: -		return output_status_unknown; -	default: -		return output_status_connected; -	} + +	return output_status_connected;  }  static struct input_res { @@ -1540,134 +1534,40 @@ intel_tv_destroy (struct drm_output *output)  }  static bool -intel_tv_format_set_property(struct drm_output *output, -			     struct drm_property *prop, uint64_t val) -{ -#if 0 -	struct intel_output *intel_output = output->driver_private; -	struct intel_tv_priv *tv_priv = intel_output->dev_priv; -	const struct tv_mode *tv_mode = -		intel_tv_mode_lookup(tv_priv->tv_format); -	int			    err; - -	if (!tv_mode) -		tv_mode = &tv_modes[0]; -	err = RRChangeOutputProperty (output->randr_output, tv_format_atom, -				      XA_ATOM, 32, PropModeReplace, 1, -				      &tv_format_name_atoms[tv_mode - tv_modes], -				      FALSE, TRUE); -	return err == Success; -#endif -	return 0; -} - -     -/** - * Configure the TV_FORMAT property to list only supported formats - * - * Unless the connector is component, list only the formats supported by - * svideo and composite - */ - -static int -intel_tv_format_configure_property(struct drm_output *output) -{ -#if 0 -	struct intel_output *intel_output = output->driver_private; -	struct intel_tv_priv *tv_priv = intel_output->dev_priv; -	Atom		    current_atoms[NUM_TV_MODES]; -	int			    num_atoms = 0; -	int			    i; -     -	if (!output->randr_output) -		return Success; - -	for (i = 0; i < NUM_TV_MODES; i++) -		if (!tv_modes[i].component_only || -		    tv_priv->type == TV_TYPE_COMPONENT) -			current_atoms[num_atoms++] = tv_format_name_atoms[i]; -     -	return RRConfigureOutputProperty(output->randr_output, tv_format_atom, -					 TRUE, FALSE, FALSE,  -					 num_atoms, (INT32 *) current_atoms); -#endif -	return 0; -} - -static void -intel_tv_create_resources(struct drm_output *output) -{ -	struct drm_device *dev = output->dev; -	struct intel_output *intel_output = output->driver_private; -	struct intel_tv_priv *tv_priv = intel_output->dev_priv; -	int i, err; - -#if 0 -	/* Set up the tv_format property, which takes effect on mode set -	 * and accepts strings that match exactly -	 */ -	tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1, -				  TRUE); - -	for (i = 0; i < NUM_TV_MODES; i++) -		tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name, -						    strlen (tv_modes[i].name), -						    TRUE); - -	err = intel_tv_format_configure_property (output); - -	if (err != 0) { -		xf86DrvMsg(dev->scrnIndex, X_ERROR, -			   "RRConfigureOutputProperty error, %d\n", err); -	} - -	/* Set the current value of the tv_format property */ -	if (!intel_tv_format_set_property (output)) -		xf86DrvMsg(dev->scrnIndex, X_ERROR, -			   "RRChangeOutputProperty error, %d\n", err); - -	for (i = 0; i < 4; i++) -	{ -		INT32	range[2]; -		margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]), -					   TRUE); - -		range[0] = 0; -		range[1] = 100; -		err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i], -						TRUE, TRUE, FALSE, 2, range); -     -		if (err != 0) -			xf86DrvMsg(dev->scrnIndex, X_ERROR, -				   "RRConfigureOutputProperty error, %d\n", err); - -		err = RRChangeOutputProperty(output->randr_output, margin_atoms[i], -					     XA_INTEGER, 32, PropModeReplace, -					     1, &tv_priv->margin[i], -					     FALSE, TRUE); -		if (err != 0) -			xf86DrvMsg(dev->scrnIndex, X_ERROR, -				   "RRChangeOutputProperty error, %d\n", err); -	} -#endif -} - -static bool  intel_tv_set_property(struct drm_output *output, struct drm_property *property,  		      uint64_t val)  {  	struct drm_device *dev = output->dev; +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv;  	int ret = 0; -     -	if (property == dev->mode_config.tv_left_margin_property || -	    property == dev->mode_config.tv_right_margin_property || -	    property == dev->mode_config.tv_top_margin_property || -	    property == dev->mode_config.tv_bottom_margin_property) { -		ret = drm_output_property_set_value(output, property, val); + +	ret = drm_output_property_set_value(output, property, val); +	if (ret < 0) +		goto out; + +	if (property == dev->mode_config.tv_left_margin_property) +		tv_priv->margin[TV_MARGIN_LEFT] = val; +	else if (property == dev->mode_config.tv_right_margin_property) +		tv_priv->margin[TV_MARGIN_RIGHT] = val; +	else if (property == dev->mode_config.tv_top_margin_property) +		tv_priv->margin[TV_MARGIN_TOP] = val; +	else if (property == dev->mode_config.tv_bottom_margin_property) +		tv_priv->margin[TV_MARGIN_BOTTOM] = val; +	else if (property == dev->mode_config.tv_mode_property) { +		if (val >= NUM_TV_MODES) { +			ret = -EINVAL; +			goto out; +		} +		tv_priv->tv_format = tv_modes[val].name; +		intel_tv_mode_set(output, NULL, NULL);  	} else { -		/* TV mode handling here */ +		ret = -EINVAL; +		goto out;  	} +	intel_tv_mode_set(output, NULL, NULL); +out:  	return ret;  } @@ -1694,6 +1594,8 @@ intel_tv_init(struct drm_device *dev)  	struct intel_output *intel_output;  	struct intel_tv_priv *tv_priv;  	u32 tv_dac_on, tv_dac_off, save_tv_dac; +	char **tv_format_names; +	int i, initial_mode = 0;  	/* FIXME: better TV detection and/or quirks */  #if 0 @@ -1744,20 +1646,47 @@ intel_tv_init(struct drm_device *dev)  	output->possible_crtcs = ((1 << 0) | (1 << 1));  	output->possible_clones = (1 << INTEL_OUTPUT_TVOUT);  	intel_output->dev_priv = tv_priv; -	tv_priv->type = TV_TYPE_UNKNOWN; +	tv_priv->type = ConnectorUnknown; -	tv_priv->tv_format = NULL; -      	/* BIOS margin values */  	tv_priv->margin[TV_MARGIN_LEFT] = 54;  	tv_priv->margin[TV_MARGIN_TOP] = 36;  	tv_priv->margin[TV_MARGIN_RIGHT] = 46;  	tv_priv->margin[TV_MARGIN_BOTTOM] = 37; -	if (!tv_priv->tv_format) -		tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL); +	tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);  	output->driver_private = intel_output;  	output->interlace_allowed = FALSE;  	output->doublescan_allowed = FALSE; + +	drm_output_attach_property(output, +				   dev->mode_config.connector_type_property, +				   ConnectorUnknown); + +	/* Create TV properties then attach current values */ +	tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, +				    DRM_MEM_DRIVER); +	if (!tv_format_names) +		goto out; +	for (i = 0; i < NUM_TV_MODES; i++) +		tv_format_names[i] = tv_modes[i].name; +	drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + +	drm_output_attach_property(output, dev->mode_config.tv_mode_property, +				   initial_mode); +	drm_output_attach_property(output, +				   dev->mode_config.tv_left_margin_property, +				   tv_priv->margin[TV_MARGIN_LEFT]); +	drm_output_attach_property(output, +				   dev->mode_config.tv_top_margin_property, +				   tv_priv->margin[TV_MARGIN_TOP]); +	drm_output_attach_property(output, +				   dev->mode_config.tv_right_margin_property, +				   tv_priv->margin[TV_MARGIN_RIGHT]); +	drm_output_attach_property(output, +				   dev->mode_config.tv_bottom_margin_property, +				   tv_priv->margin[TV_MARGIN_BOTTOM]); +out: +	drm_sysfs_output_add(output);  } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 64faac9b..e32c36f1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -554,7 +554,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define I915_VBLANK_INTERRUPT_ENABLE	(1UL<<17)  #define I915_HOTPLUG_INTERRUPT_ENABLE	(1UL<<26) +#define I915_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18)  #define I915_HOTPLUG_CLEAR		(1UL<<10) +#define I915_HOTPLUG_TV_CLEAR		(1UL<<2)  #define I915_VBLANK_CLEAR		(1UL<<1)  /* @@ -669,6 +671,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define I915_LEGACY_BLC_EVENT_STATUS		(1UL<<6)  #define I915_ODD_FIELD_INTERRUPT_STATUS		(1UL<<5)  #define I915_EVEN_FIELD_INTERRUPT_STATUS	(1UL<<4) +#define I915_HOTPLUG_TV_INTERRUPT_STATUS	(1UL<<2)  #define I915_START_VBLANK_INTERRUPT_STATUS	(1UL<<2)	/* 965 or later */  #define I915_VBLANK_INTERRUPT_STATUS		(1UL<<1)  #define I915_OVERLAY_UPDATED_STATUS		(1UL<<0) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index a76acb4e..ce6f1656 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -265,6 +265,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)  		drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM");  		drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); +		dev->devname = DRIVER_NAME;  		drm_irq_install(dev);  	} diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index abd8a7d3..8f136c8f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -424,11 +424,41 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)  #define HOTPLUG_CMD_CRT_DIS 2  #define HOTPLUG_CMD_SDVOB 4  #define HOTPLUG_CMD_SDVOC 8 +#define HOTPLUG_CMD_TV 16  static struct drm_device *hotplug_dev;  static int hotplug_cmd = 0;  static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; +static void i915_hotplug_tv(struct drm_device *dev) +{ +	struct drm_output *output; +	struct intel_output *iout; +	enum drm_output_status status; + +	mutex_lock(&dev->mode_config.mutex); + +	/* find the crt output */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		iout = output->driver_private; +		if (iout->type == INTEL_OUTPUT_TVOUT) +			break; +		else +			iout = 0; +	} + +	if (iout == 0) +		goto unlock; + +	/* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */ +	status = output->funcs->detect(output); +	drm_hotplug_stage_two(dev, output, +			      status == output_status_connected ? 1 : 0); + +unlock: +	mutex_unlock(&dev->mode_config.mutex); +} +  static void i915_hotplug_crt(struct drm_device *dev, bool isconnected)  {  	struct drm_output *output; @@ -493,8 +523,10 @@ static void i915_hotplug_work_func(struct work_struct *work)  	int crtDis;  	int sdvoB;  	int sdvoC; +	int tv;  	spin_lock(&hotplug_lock); +	tv = hotplug_cmd & HOTPLUG_CMD_TV;  	crt = hotplug_cmd & HOTPLUG_CMD_CRT;  	crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS;  	sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; @@ -502,6 +534,8 @@ static void i915_hotplug_work_func(struct work_struct *work)  	hotplug_cmd = 0;  	spin_unlock(&hotplug_lock); +	if (tv) +		i915_hotplug_tv(dev);  	if (crt)  		i915_hotplug_crt(dev, true);  	if (crtDis) @@ -527,6 +561,14 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat)  	hotplug_dev = dev; +	if (stat & TV_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("TV event\n"); + +		spin_lock(&hotplug_lock); +		hotplug_cmd |= HOTPLUG_CMD_TV; +		spin_unlock(&hotplug_lock); +	} +  	if (stat & CRT_HOTPLUG_INT_STATUS) {  		DRM_DEBUG("CRT event\n"); @@ -584,12 +626,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  	DRM_DEBUG("flag=%08x\n", iir);  #endif  	if (iir == 0) { +#if 0  		DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n",  			   iir,  			   I915_READ(I915REG_INT_MASK_R),  			   I915_READ(I915REG_INT_ENABLE_R),  			   I915_READ(I915REG_PIPEASTAT),  			   I915_READ(I915REG_PIPEBSTAT)); +#endif  		return IRQ_NONE;  	} @@ -607,7 +651,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  		}  		/* This is a global event, and not a pipe A event */ -		if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) +		if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) || +		    (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS))  			hotplug = 1;  		I915_WRITE(I915REG_PIPEASTAT, pipea_stats); @@ -656,8 +701,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  		DRM_INFO("Hotplug event received\n");  		if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { -			temp2 |= SDVOB_HOTPLUG_INT_STATUS | -				 SDVOC_HOTPLUG_INT_STATUS; +			if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) +				temp2 |= SDVOB_HOTPLUG_INT_STATUS | +					SDVOC_HOTPLUG_INT_STATUS; +			if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) +				temp2 |= TV_HOTPLUG_INT_STATUS;  		} else {  			temp2 = I915_READ(PORT_HOTPLUG_STAT); @@ -898,7 +946,11 @@ void i915_enable_interrupt (struct drm_device *dev)  			dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;  		/* Enable global interrupts for hotplug - not a pipeA event */ -		I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); +		I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | +			   I915_HOTPLUG_INTERRUPT_ENABLE | +			   I915_HOTPLUG_TV_INTERRUPT_ENABLE | +			   I915_HOTPLUG_TV_CLEAR | +			   I915_HOTPLUG_CLEAR);  	}  	if (dev_priv->irq_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) { | 
