summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerome Glisse <glisse@freedesktop.org>2008-04-12 00:15:47 +0200
committerJerome Glisse <glisse@freedesktop.org>2008-04-12 00:15:47 +0200
commit6cc2d7e7ae92bbac630d0053fc214521ce610dc6 (patch)
treed222f8edd276d7dea539111118b7c703153ae7a1
parent5891b0bd2ae441d738e78737a4c4826bd2e60b43 (diff)
parent3b32ee36ae58f733f281a2fa569ea8a8a926bb6d (diff)
Merge branch 'modesetting-101' of ssh://git.freedesktop.org/git/mesa/drm into modesetting-101
-rw-r--r--linux-core/drmP.h4
-rw-r--r--linux-core/drm_compat.h9
-rw-r--r--linux-core/drm_crtc.c95
-rw-r--r--linux-core/drm_crtc.h38
-rw-r--r--linux-core/drm_edid.c28
-rw-r--r--linux-core/drm_sysfs.c199
-rw-r--r--linux-core/intel_crt.c2
-rw-r--r--linux-core/intel_display.c148
-rw-r--r--linux-core/intel_drv.h7
-rw-r--r--linux-core/intel_lvds.c28
-rw-r--r--linux-core/intel_sdvo.c35
-rw-r--r--linux-core/intel_tv.c277
-rw-r--r--shared-core/i915_drv.h3
-rw-r--r--shared-core/i915_init.c1
-rw-r--r--shared-core/i915_irq.c60
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)) {