/drivers/video/drm/drm_crtc.c |
---|
706,7 → 706,6 |
connector->connector_type = connector_type; |
connector->connector_type_id = |
++drm_connector_enum_list[connector_type].count; /* TODO */ |
INIT_LIST_HEAD(&connector->user_modes); |
INIT_LIST_HEAD(&connector->probed_modes); |
INIT_LIST_HEAD(&connector->modes); |
connector->edid_blob_ptr = NULL; |
747,9 → 746,6 |
list_for_each_entry_safe(mode, t, &connector->modes, head) |
drm_mode_remove(connector, mode); |
list_for_each_entry_safe(mode, t, &connector->user_modes, head) |
drm_mode_remove(connector, mode); |
drm_mode_object_put(dev, &connector->base); |
list_del(&connector->head); |
dev->mode_config.num_connector--; |
1120,46 → 1116,8 |
} |
EXPORT_SYMBOL(drm_mode_create_dirty_info_property); |
/** |
* drm_mode_config_init - initialize DRM mode_configuration structure |
* @dev: DRM device |
* |
* Initialize @dev's mode_config structure, used for tracking the graphics |
* configuration of @dev. |
* |
* Since this initializes the modeset locks, no locking is possible. Which is no |
* problem, since this should happen single threaded at init time. It is the |
* driver's problem to ensure this guarantee. |
* |
*/ |
void drm_mode_config_init(struct drm_device *dev) |
static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) |
{ |
mutex_init(&dev->mode_config.mutex); |
mutex_init(&dev->mode_config.idr_mutex); |
mutex_init(&dev->mode_config.fb_lock); |
INIT_LIST_HEAD(&dev->mode_config.fb_list); |
INIT_LIST_HEAD(&dev->mode_config.crtc_list); |
INIT_LIST_HEAD(&dev->mode_config.connector_list); |
INIT_LIST_HEAD(&dev->mode_config.encoder_list); |
INIT_LIST_HEAD(&dev->mode_config.property_list); |
INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |
INIT_LIST_HEAD(&dev->mode_config.plane_list); |
idr_init(&dev->mode_config.crtc_idr); |
drm_modeset_lock_all(dev); |
drm_mode_create_standard_connector_properties(dev); |
drm_modeset_unlock_all(dev); |
/* Just to be sure */ |
dev->mode_config.num_fb = 0; |
dev->mode_config.num_connector = 0; |
dev->mode_config.num_crtc = 0; |
dev->mode_config.num_encoder = 0; |
} |
EXPORT_SYMBOL(drm_mode_config_init); |
int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) |
{ |
uint32_t total_objects = 0; |
total_objects += dev->mode_config.num_crtc; |
1203,69 → 1161,6 |
EXPORT_SYMBOL(drm_mode_group_init_legacy_group); |
/** |
* drm_mode_config_cleanup - free up DRM mode_config info |
* @dev: DRM device |
* |
* Free up all the connectors and CRTCs associated with this DRM device, then |
* free up the framebuffers and associated buffer objects. |
* |
* Note that since this /should/ happen single-threaded at driver/device |
* teardown time, no locking is required. It's the driver's job to ensure that |
* this guarantee actually holds true. |
* |
* FIXME: cleanup any dangling user buffer objects too |
*/ |
void drm_mode_config_cleanup(struct drm_device *dev) |
{ |
struct drm_connector *connector, *ot; |
struct drm_crtc *crtc, *ct; |
struct drm_encoder *encoder, *enct; |
struct drm_framebuffer *fb, *fbt; |
struct drm_property *property, *pt; |
struct drm_plane *plane, *plt; |
list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, |
head) { |
encoder->funcs->destroy(encoder); |
} |
list_for_each_entry_safe(connector, ot, |
&dev->mode_config.connector_list, head) { |
connector->funcs->destroy(connector); |
} |
list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, |
head) { |
drm_property_destroy(dev, property); |
} |
/* |
* Single-threaded teardown context, so it's not required to grab the |
* fb_lock to protect against concurrent fb_list access. Contrary, it |
* would actually deadlock with the drm_framebuffer_cleanup function. |
* |
* Also, if there are any framebuffers left, that's a driver leak now, |
* so politely WARN about this. |
*/ |
WARN_ON(!list_empty(&dev->mode_config.fb_list)); |
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { |
drm_framebuffer_remove(fb); |
} |
list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, |
head) { |
plane->funcs->destroy(plane); |
} |
list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { |
crtc->funcs->destroy(crtc); |
} |
idr_destroy(&dev->mode_config.crtc_idr); |
} |
EXPORT_SYMBOL(drm_mode_config_cleanup); |
/** |
* drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo |
* @out: drm_mode_modeinfo struct to return to the user |
* @in: drm_display_mode to use |
2722,195 → 2617,7 |
} |
#endif |
/** |
* drm_mode_attachmode - add a mode to the user mode list |
* @dev: DRM device |
* @connector: connector to add the mode to |
* @mode: mode to add |
* |
* Add @mode to @connector's user mode list. |
*/ |
static void drm_mode_attachmode(struct drm_device *dev, |
struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
list_add_tail(&mode->head, &connector->user_modes); |
} |
int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, |
const struct drm_display_mode *mode) |
{ |
struct drm_connector *connector; |
int ret = 0; |
struct drm_display_mode *dup_mode, *next; |
LIST_HEAD(list); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (!connector->encoder) |
continue; |
if (connector->encoder->crtc == crtc) { |
dup_mode = drm_mode_duplicate(dev, mode); |
if (!dup_mode) { |
ret = -ENOMEM; |
goto out; |
} |
list_add_tail(&dup_mode->head, &list); |
} |
} |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (!connector->encoder) |
continue; |
if (connector->encoder->crtc == crtc) |
list_move_tail(list.next, &connector->user_modes); |
} |
WARN_ON(!list_empty(&list)); |
out: |
list_for_each_entry_safe(dup_mode, next, &list, head) |
drm_mode_destroy(dev, dup_mode); |
return ret; |
} |
EXPORT_SYMBOL(drm_mode_attachmode_crtc); |
static int drm_mode_detachmode(struct drm_device *dev, |
struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
int found = 0; |
int ret = 0; |
struct drm_display_mode *match_mode, *t; |
list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { |
if (drm_mode_equal(match_mode, mode)) { |
list_del(&match_mode->head); |
drm_mode_destroy(dev, match_mode); |
found = 1; |
break; |
} |
} |
if (!found) |
ret = -EINVAL; |
return ret; |
} |
int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) |
{ |
struct drm_connector *connector; |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
drm_mode_detachmode(dev, connector, mode); |
} |
return 0; |
} |
EXPORT_SYMBOL(drm_mode_detachmode_crtc); |
#if 0 |
/** |
* drm_fb_attachmode - Attach a user mode to an connector |
* @dev: drm device for the ioctl |
* @data: data pointer for the ioctl |
* @file_priv: drm file for the ioctl call |
* |
* This attaches a user specified mode to an connector. |
* Called by the user via ioctl. |
* |
* RETURNS: |
* Zero on success, errno on failure. |
*/ |
int drm_mode_attachmode_ioctl(struct drm_device *dev, |
void *data, struct drm_file *file_priv) |
{ |
struct drm_mode_mode_cmd *mode_cmd = data; |
struct drm_connector *connector; |
struct drm_display_mode *mode; |
struct drm_mode_object *obj; |
struct drm_mode_modeinfo *umode = &mode_cmd->mode; |
int ret; |
if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
return -EINVAL; |
drm_modeset_lock_all(dev); |
obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
if (!obj) { |
ret = -EINVAL; |
goto out; |
} |
connector = obj_to_connector(obj); |
mode = drm_mode_create(dev); |
if (!mode) { |
ret = -ENOMEM; |
goto out; |
} |
ret = drm_crtc_convert_umode(mode, umode); |
if (ret) { |
DRM_DEBUG_KMS("Invalid mode\n"); |
drm_mode_destroy(dev, mode); |
goto out; |
} |
drm_mode_attachmode(dev, connector, mode); |
out: |
drm_modeset_unlock_all(dev); |
return ret; |
} |
/** |
* drm_fb_detachmode - Detach a user specified mode from an connector |
* @dev: drm device for the ioctl |
* @data: data pointer for the ioctl |
* @file_priv: drm file for the ioctl call |
* |
* Called by the user via ioctl. |
* |
* RETURNS: |
* Zero on success, errno on failure. |
*/ |
int drm_mode_detachmode_ioctl(struct drm_device *dev, |
void *data, struct drm_file *file_priv) |
{ |
struct drm_mode_object *obj; |
struct drm_mode_mode_cmd *mode_cmd = data; |
struct drm_connector *connector; |
struct drm_display_mode mode; |
struct drm_mode_modeinfo *umode = &mode_cmd->mode; |
int ret; |
if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
return -EINVAL; |
drm_modeset_lock_all(dev); |
obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
if (!obj) { |
ret = -EINVAL; |
goto out; |
} |
connector = obj_to_connector(obj); |
ret = drm_crtc_convert_umode(&mode, umode); |
if (ret) { |
DRM_DEBUG_KMS("Invalid mode\n"); |
goto out; |
} |
ret = drm_mode_detachmode(dev, connector, &mode); |
out: |
drm_modeset_unlock_all(dev); |
return ret; |
} |
#endif |
struct drm_property *drm_property_create(struct drm_device *dev, int flags, |
const char *name, int num_values) |
{ |
3892,3 → 3599,42 |
} |
} |
EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); |
/** |
* drm_mode_config_init - initialize DRM mode_configuration structure |
* @dev: DRM device |
* |
* Initialize @dev's mode_config structure, used for tracking the graphics |
* configuration of @dev. |
* |
* Since this initializes the modeset locks, no locking is possible. Which is no |
* problem, since this should happen single threaded at init time. It is the |
* driver's problem to ensure this guarantee. |
* |
*/ |
void drm_mode_config_init(struct drm_device *dev) |
{ |
mutex_init(&dev->mode_config.mutex); |
mutex_init(&dev->mode_config.idr_mutex); |
mutex_init(&dev->mode_config.fb_lock); |
INIT_LIST_HEAD(&dev->mode_config.fb_list); |
INIT_LIST_HEAD(&dev->mode_config.crtc_list); |
INIT_LIST_HEAD(&dev->mode_config.connector_list); |
INIT_LIST_HEAD(&dev->mode_config.encoder_list); |
INIT_LIST_HEAD(&dev->mode_config.property_list); |
INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |
INIT_LIST_HEAD(&dev->mode_config.plane_list); |
idr_init(&dev->mode_config.crtc_idr); |
drm_modeset_lock_all(dev); |
drm_mode_create_standard_connector_properties(dev); |
drm_modeset_unlock_all(dev); |
/* Just to be sure */ |
dev->mode_config.num_fb = 0; |
dev->mode_config.num_connector = 0; |
dev->mode_config.num_crtc = 0; |
dev->mode_config.num_encoder = 0; |
} |
EXPORT_SYMBOL(drm_mode_config_init); |
/drivers/video/drm/drm_crtc_helper.c |
---|
651,6 → 651,9 |
} else if (set->fb->bits_per_pixel != |
set->crtc->fb->bits_per_pixel) { |
mode_changed = true; |
} else if (set->fb->pixel_format != |
set->crtc->fb->pixel_format) { |
mode_changed = true; |
} else |
fb_changed = true; |
} |
/drivers/video/drm/drm_edid.c |
---|
587,284 → 587,348 |
/* 1 - 640x480@60Hz */ |
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, |
752, 800, 0, 480, 490, 492, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 2 - 720x480@60Hz */ |
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, |
798, 858, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 3 - 720x480@60Hz */ |
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, |
798, 858, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 4 - 1280x720@60Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, |
1430, 1650, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 60, }, |
/* 5 - 1920x1080i@60Hz */ |
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, |
2052, 2200, 0, 1080, 1084, 1094, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 60, }, |
/* 6 - 1440x480i@60Hz */ |
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, |
1602, 1716, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 60, }, |
/* 7 - 1440x480i@60Hz */ |
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, |
1602, 1716, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 60, }, |
/* 8 - 1440x240@60Hz */ |
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, |
1602, 1716, 0, 240, 244, 247, 262, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 60, }, |
/* 9 - 1440x240@60Hz */ |
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, |
1602, 1716, 0, 240, 244, 247, 262, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 60, }, |
/* 10 - 2880x480i@60Hz */ |
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, |
3204, 3432, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 60, }, |
/* 11 - 2880x480i@60Hz */ |
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, |
3204, 3432, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 60, }, |
/* 12 - 2880x240@60Hz */ |
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, |
3204, 3432, 0, 240, 244, 247, 262, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 13 - 2880x240@60Hz */ |
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, |
3204, 3432, 0, 240, 244, 247, 262, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 14 - 1440x480@60Hz */ |
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, |
1596, 1716, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 15 - 1440x480@60Hz */ |
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, |
1596, 1716, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 16 - 1920x1080@60Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, |
2052, 2200, 0, 1080, 1084, 1089, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 60, }, |
/* 17 - 720x576@50Hz */ |
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, |
796, 864, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 18 - 720x576@50Hz */ |
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, |
796, 864, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 19 - 1280x720@50Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, |
1760, 1980, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 50, }, |
/* 20 - 1920x1080i@50Hz */ |
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, |
2492, 2640, 0, 1080, 1084, 1094, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 50, }, |
/* 21 - 1440x576i@50Hz */ |
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, |
1590, 1728, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 50, }, |
/* 22 - 1440x576i@50Hz */ |
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, |
1590, 1728, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 50, }, |
/* 23 - 1440x288@50Hz */ |
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, |
1590, 1728, 0, 288, 290, 293, 312, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 50, }, |
/* 24 - 1440x288@50Hz */ |
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, |
1590, 1728, 0, 288, 290, 293, 312, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 50, }, |
/* 25 - 2880x576i@50Hz */ |
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, |
3180, 3456, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 50, }, |
/* 26 - 2880x576i@50Hz */ |
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, |
3180, 3456, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 50, }, |
/* 27 - 2880x288@50Hz */ |
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, |
3180, 3456, 0, 288, 290, 293, 312, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 28 - 2880x288@50Hz */ |
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, |
3180, 3456, 0, 288, 290, 293, 312, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 29 - 1440x576@50Hz */ |
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, |
1592, 1728, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 30 - 1440x576@50Hz */ |
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, |
1592, 1728, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 31 - 1920x1080@50Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, |
2492, 2640, 0, 1080, 1084, 1089, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 50, }, |
/* 32 - 1920x1080@24Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, |
2602, 2750, 0, 1080, 1084, 1089, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 24, }, |
/* 33 - 1920x1080@25Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, |
2492, 2640, 0, 1080, 1084, 1089, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 25, }, |
/* 34 - 1920x1080@30Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, |
2052, 2200, 0, 1080, 1084, 1089, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 30, }, |
/* 35 - 2880x480@60Hz */ |
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, |
3192, 3432, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 36 - 2880x480@60Hz */ |
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, |
3192, 3432, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 60, }, |
/* 37 - 2880x576@50Hz */ |
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, |
3184, 3456, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 38 - 2880x576@50Hz */ |
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, |
3184, 3456, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 50, }, |
/* 39 - 1920x1080i@50Hz */ |
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, |
2120, 2304, 0, 1080, 1126, 1136, 1250, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 50, }, |
/* 40 - 1920x1080i@100Hz */ |
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, |
2492, 2640, 0, 1080, 1084, 1094, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 100, }, |
/* 41 - 1280x720@100Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, |
1760, 1980, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 100, }, |
/* 42 - 720x576@100Hz */ |
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, |
796, 864, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 100, }, |
/* 43 - 720x576@100Hz */ |
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, |
796, 864, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 100, }, |
/* 44 - 1440x576i@100Hz */ |
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, |
1590, 1728, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 100, }, |
/* 45 - 1440x576i@100Hz */ |
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, |
1590, 1728, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 100, }, |
/* 46 - 1920x1080i@120Hz */ |
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, |
2052, 2200, 0, 1080, 1084, 1094, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
DRM_MODE_FLAG_INTERLACE), |
.vrefresh = 120, }, |
/* 47 - 1280x720@120Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, |
1430, 1650, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 120, }, |
/* 48 - 720x480@120Hz */ |
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, |
798, 858, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 120, }, |
/* 49 - 720x480@120Hz */ |
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, |
798, 858, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 120, }, |
/* 50 - 1440x480i@120Hz */ |
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, |
1602, 1716, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 120, }, |
/* 51 - 1440x480i@120Hz */ |
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, |
1602, 1716, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 120, }, |
/* 52 - 720x576@200Hz */ |
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, |
796, 864, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 200, }, |
/* 53 - 720x576@200Hz */ |
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, |
796, 864, 0, 576, 581, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 200, }, |
/* 54 - 1440x576i@200Hz */ |
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, |
1590, 1728, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 200, }, |
/* 55 - 1440x576i@200Hz */ |
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, |
1590, 1728, 0, 576, 580, 586, 625, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 200, }, |
/* 56 - 720x480@240Hz */ |
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, |
798, 858, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 240, }, |
/* 57 - 720x480@240Hz */ |
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, |
798, 858, 0, 480, 489, 495, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), |
.vrefresh = 240, }, |
/* 58 - 1440x480i@240 */ |
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, |
1602, 1716, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 240, }, |
/* 59 - 1440x480i@240 */ |
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, |
1602, 1716, 0, 480, 488, 494, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), |
.vrefresh = 240, }, |
/* 60 - 1280x720@24Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, |
3080, 3300, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 24, }, |
/* 61 - 1280x720@25Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, |
3740, 3960, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 25, }, |
/* 62 - 1280x720@30Hz */ |
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, |
3080, 3300, 0, 720, 725, 730, 750, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 30, }, |
/* 63 - 1920x1080@120Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, |
2052, 2200, 0, 1080, 1084, 1089, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 120, }, |
/* 64 - 1920x1080@100Hz */ |
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, |
2492, 2640, 0, 1080, 1084, 1094, 1125, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), |
.vrefresh = 100, }, |
}; |
/*** DDC fetch and block validation ***/ |
2266,13 → 2330,34 |
*/ |
u8 drm_match_cea_mode(const struct drm_display_mode *to_match) |
{ |
struct drm_display_mode *cea_mode; |
u8 mode; |
if (!to_match->clock) |
return 0; |
for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { |
cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode]; |
const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; |
unsigned int clock1, clock2; |
if (drm_mode_equal(to_match, cea_mode)) |
clock1 = clock2 = cea_mode->clock; |
/* Check both 60Hz and 59.94Hz */ |
if (cea_mode->vrefresh % 6 == 0) { |
/* |
* edid_cea_modes contains the 59.94Hz |
* variant for 240 and 480 line modes, |
* and the 60Hz variant otherwise. |
*/ |
if (cea_mode->vdisplay == 240 || |
cea_mode->vdisplay == 480) |
clock1 = clock1 * 1001 / 1000; |
else |
clock2 = DIV_ROUND_UP(clock2 * 1000, 1001); |
} |
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || |
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && |
drm_mode_equal_no_clocks(to_match, cea_mode)) |
return mode + 1; |
} |
return 0; |
2294,6 → 2379,7 |
newmode = drm_mode_duplicate(dev, |
&edid_cea_modes[cea_mode]); |
if (newmode) { |
newmode->vrefresh = 0; |
drm_mode_probed_add(connector, newmode); |
modes++; |
} |
2511,6 → 2597,65 |
EXPORT_SYMBOL(drm_edid_to_eld); |
/** |
* drm_edid_to_sad - extracts SADs from EDID |
* @edid: EDID to parse |
* @sads: pointer that will be set to the extracted SADs |
* |
* Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it. |
* Note: returned pointer needs to be kfreed |
* |
* Return number of found SADs or negative number on error. |
*/ |
int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads) |
{ |
int count = 0; |
int i, start, end, dbl; |
u8 *cea; |
cea = drm_find_cea_extension(edid); |
if (!cea) { |
DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); |
return -ENOENT; |
} |
if (cea_revision(cea) < 3) { |
DRM_DEBUG_KMS("SAD: wrong CEA revision\n"); |
return -ENOTSUPP; |
} |
if (cea_db_offsets(cea, &start, &end)) { |
DRM_DEBUG_KMS("SAD: invalid data block offsets\n"); |
return -EPROTO; |
} |
for_each_cea_db(cea, i, start, end) { |
u8 *db = &cea[i]; |
if (cea_db_tag(db) == AUDIO_BLOCK) { |
int j; |
dbl = cea_db_payload_len(db); |
count = dbl / 3; /* SAD is 3B */ |
*sads = kcalloc(count, sizeof(**sads), GFP_KERNEL); |
if (!*sads) |
return -ENOMEM; |
for (j = 0; j < count; j++) { |
u8 *sad = &db[1 + j * 3]; |
(*sads)[j].format = (sad[0] & 0x78) >> 3; |
(*sads)[j].channels = sad[0] & 0x7; |
(*sads)[j].freq = sad[1] & 0x7F; |
(*sads)[j].byte2 = sad[2]; |
} |
break; |
} |
} |
return count; |
} |
EXPORT_SYMBOL(drm_edid_to_sad); |
/** |
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond |
* @connector: connector associated with the HDMI/DP sink |
* @mode: the display mode |
/drivers/video/drm/drm_fb_helper.c |
---|
863,7 → 863,49 |
return cmdline_mode->specified; |
} |
static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
int width, int height) |
{ |
struct drm_cmdline_mode *cmdline_mode; |
struct drm_display_mode *mode = NULL; |
return NULL; |
cmdline_mode = &fb_helper_conn->cmdline_mode; |
if (cmdline_mode->specified == false) |
return mode; |
/* attempt to find a matching mode in the list of modes |
* we have gotten so far, if not add a CVT mode that conforms |
*/ |
if (cmdline_mode->rb || cmdline_mode->margins) |
goto create_mode; |
list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { |
/* check width/height */ |
if (mode->hdisplay != cmdline_mode->xres || |
mode->vdisplay != cmdline_mode->yres) |
continue; |
if (cmdline_mode->refresh_specified) { |
if (mode->vrefresh != cmdline_mode->refresh) |
continue; |
} |
if (cmdline_mode->interlace) { |
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) |
continue; |
} |
return mode; |
} |
create_mode: |
mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, |
cmdline_mode); |
list_add(&mode->head, &fb_helper_conn->connector->modes); |
return mode; |
} |
static bool drm_connector_enabled(struct drm_connector *connector, bool strict) |
{ |
bool enable; |
900,7 → 942,79 |
} |
} |
static bool drm_target_cloned(struct drm_fb_helper *fb_helper, |
struct drm_display_mode **modes, |
bool *enabled, int width, int height) |
{ |
int count, i, j; |
bool can_clone = false; |
struct drm_fb_helper_connector *fb_helper_conn; |
struct drm_display_mode *dmt_mode, *mode; |
/* only contemplate cloning in the single crtc case */ |
if (fb_helper->crtc_count > 1) |
return false; |
count = 0; |
for (i = 0; i < fb_helper->connector_count; i++) { |
if (enabled[i]) |
count++; |
} |
/* only contemplate cloning if more than one connector is enabled */ |
if (count <= 1) |
return false; |
/* check the command line or if nothing common pick 1024x768 */ |
can_clone = true; |
for (i = 0; i < fb_helper->connector_count; i++) { |
if (!enabled[i]) |
continue; |
fb_helper_conn = fb_helper->connector_info[i]; |
modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
if (!modes[i]) { |
can_clone = false; |
break; |
} |
for (j = 0; j < i; j++) { |
if (!enabled[j]) |
continue; |
if (!drm_mode_equal(modes[j], modes[i])) |
can_clone = false; |
} |
} |
if (can_clone) { |
DRM_DEBUG_KMS("can clone using command line\n"); |
return true; |
} |
/* try and find a 1024x768 mode on each connector */ |
can_clone = true; |
dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false); |
for (i = 0; i < fb_helper->connector_count; i++) { |
if (!enabled[i]) |
continue; |
fb_helper_conn = fb_helper->connector_info[i]; |
list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { |
if (drm_mode_equal(mode, dmt_mode)) |
modes[i] = mode; |
} |
if (!modes[i]) |
can_clone = false; |
} |
if (can_clone) { |
DRM_DEBUG_KMS("can clone using 1024x768\n"); |
return true; |
} |
DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); |
return false; |
} |
static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
struct drm_display_mode **modes, |
bool *enabled, int width, int height) |
918,10 → 1032,7 |
fb_helper_conn->connector->base.id); |
/* got for command line mode first */ |
// modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
modes[i] = NULL; |
modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
if (!modes[i]) { |
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", |
fb_helper_conn->connector->base.id); |
1029,7 → 1140,7 |
struct drm_mode_set *modeset; |
bool *enabled; |
int width, height; |
int i, ret; |
int i; |
DRM_DEBUG_KMS("\n"); |
1050,19 → 1161,23 |
drm_enable_connectors(fb_helper, enabled); |
//ret = drm_target_cloned(fb_helper, modes, enabled, width, height); |
if (!(fb_helper->funcs->initial_config && |
fb_helper->funcs->initial_config(fb_helper, crtcs, modes, |
enabled, width, height))) { |
memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); |
memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); |
ret = 0; |
if (!ret) { |
ret = drm_target_preferred(fb_helper, modes, enabled, width, height); |
if (!ret) |
if (!drm_target_cloned(fb_helper, |
modes, enabled, width, height) && |
!drm_target_preferred(fb_helper, |
modes, enabled, width, height)) |
DRM_ERROR("Unable to find initial modes\n"); |
} |
DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); |
DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", |
width, height); |
drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); |
} |
/* need to set the modesets up here for use later */ |
/* fill out the connector<->crtc mappings into the modesets */ |
/drivers/video/drm/drm_modes.c |
---|
504,7 → 504,7 |
} |
EXPORT_SYMBOL(drm_gtf_mode); |
#if IS_ENABLED(CONFIG_VIDEOMODE) |
#ifdef CONFIG_VIDEOMODE_HELPERS |
int drm_display_mode_from_videomode(const struct videomode *vm, |
struct drm_display_mode *dmode) |
{ |
521,17 → 521,17 |
dmode->clock = vm->pixelclock / 1000; |
dmode->flags = 0; |
if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH) |
if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH) |
dmode->flags |= DRM_MODE_FLAG_PHSYNC; |
else if (vm->dmt_flags & VESA_DMT_HSYNC_LOW) |
else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW) |
dmode->flags |= DRM_MODE_FLAG_NHSYNC; |
if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH) |
if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) |
dmode->flags |= DRM_MODE_FLAG_PVSYNC; |
else if (vm->dmt_flags & VESA_DMT_VSYNC_LOW) |
else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW) |
dmode->flags |= DRM_MODE_FLAG_NVSYNC; |
if (vm->data_flags & DISPLAY_FLAGS_INTERLACED) |
if (vm->flags & DISPLAY_FLAGS_INTERLACED) |
dmode->flags |= DRM_MODE_FLAG_INTERLACE; |
if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN) |
if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN) |
dmode->flags |= DRM_MODE_FLAG_DBLSCAN; |
drm_mode_set_name(dmode); |
538,9 → 538,8 |
return 0; |
} |
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); |
#endif |
#if IS_ENABLED(CONFIG_OF_VIDEOMODE) |
#ifdef CONFIG_OF |
/** |
* of_get_drm_display_mode - get a drm_display_mode from devicetree |
* @np: device_node with the timing specification |
570,7 → 569,8 |
return 0; |
} |
EXPORT_SYMBOL_GPL(of_get_drm_display_mode); |
#endif |
#endif /* CONFIG_OF */ |
#endif /* CONFIG_VIDEOMODE_HELPERS */ |
/** |
* drm_mode_set_name - set the name on a mode |
846,6 → 846,26 |
} else if (mode1->clock != mode2->clock) |
return false; |
return drm_mode_equal_no_clocks(mode1, mode2); |
} |
EXPORT_SYMBOL(drm_mode_equal); |
/** |
* drm_mode_equal_no_clocks - test modes for equality |
* @mode1: first mode |
* @mode2: second mode |
* |
* LOCKING: |
* None. |
* |
* Check to see if @mode1 and @mode2 are equivalent, but |
* don't check the pixel clocks. |
* |
* RETURNS: |
* True if the modes are equal, false otherwise. |
*/ |
bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) |
{ |
if (mode1->hdisplay == mode2->hdisplay && |
mode1->hsync_start == mode2->hsync_start && |
mode1->hsync_end == mode2->hsync_end && |
861,7 → 881,7 |
return false; |
} |
EXPORT_SYMBOL(drm_mode_equal); |
EXPORT_SYMBOL(drm_mode_equal_no_clocks); |
/** |
* drm_mode_validate_size - make sure modes adhere to size constraints |
/drivers/video/drm/drm_pci.c |
---|
94,8 → 94,6 |
if (!dev->pdev) |
return -EINVAL; |
if (!pci_is_pcie(dev->pdev)) |
return -EINVAL; |
return -EINVAL; |
/drivers/video/drm/i915/i915_dma.c |
---|
1177,6 → 1177,10 |
/* Always safe in the mode setting case. */ |
/* FIXME: do pre/post-mode set stuff in core KMS code */ |
dev->vblank_disable_allowed = 1; |
if (INTEL_INFO(dev)->num_pipes == 0) { |
dev_priv->mm.suspended = 0; |
return 0; |
} |
ret = intel_fbdev_init(dev); |
if (ret) |
1243,6 → 1247,22 |
} |
/** |
* intel_early_sanitize_regs - clean up BIOS state |
* @dev: DRM device |
* |
* This function must be called before we do any I915_READ or I915_WRITE. Its |
* purpose is to clean up any state left by the BIOS that may affect us when |
* reading and/or writing registers. |
*/ |
static void intel_early_sanitize_regs(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
if (IS_HASWELL(dev)) |
I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); |
} |
/** |
* i915_driver_load - setup chip and create an initial config |
* @dev: DRM device |
* @flags: startup flags |
1278,24 → 1298,6 |
goto free_priv; |
} |
ret = i915_gem_gtt_init(dev); |
if (ret) |
goto put_bridge; |
pci_set_master(dev->pdev); |
/* overlay on gen2 is broken and can't address above 1G */ |
/* 965GM sometimes incorrectly writes to hardware status page (HWS) |
* using 32bit addressing, overwriting memory if HWS is located |
* above 4GB. |
* |
* The documentation also mentions an issue with undefined |
* behaviour if any general state is accessed within a page above 4GB, |
* which also needs to be handled carefully. |
*/ |
mmio_bar = IS_GEN2(dev) ? 1 : 0; |
/* Before gen4, the registers and the GTT are behind different BARs. |
* However, from gen4 onwards, the registers and the GTT are shared |
1313,13 → 1315,32 |
if (!dev_priv->regs) { |
DRM_ERROR("failed to map registers\n"); |
ret = -EIO; |
goto put_gmch; |
goto put_bridge; |
} |
intel_early_sanitize_regs(dev); |
ret = i915_gem_gtt_init(dev); |
if (ret) |
goto put_bridge; |
pci_set_master(dev->pdev); |
/* overlay on gen2 is broken and can't address above 1G */ |
/* 965GM sometimes incorrectly writes to hardware status page (HWS) |
* using 32bit addressing, overwriting memory if HWS is located |
* above 4GB. |
* |
* The documentation also mentions an issue with undefined |
* behaviour if any general state is accessed within a page above 4GB, |
* which also needs to be handled carefully. |
*/ |
aperture_size = dev_priv->gtt.mappable_end; |
/* The i915 workqueue is primarily used for batched retirement of |
* requests (and thus managing bo) once the task has been completed |
* by the GPU. i915_gem_retire_requests() is called directly when we |
1376,12 → 1397,9 |
mutex_init(&dev_priv->rps.hw_lock); |
mutex_init(&dev_priv->modeset_restore_lock); |
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) |
dev_priv->num_pipe = 3; |
else if (IS_MOBILE(dev) || !IS_GEN2(dev)) |
dev_priv->num_pipe = 2; |
else |
dev_priv->num_pipe = 1; |
dev_priv->num_plane = 1; |
if (IS_VALLEYVIEW(dev)) |
dev_priv->num_plane = 2; |
// ret = drm_vblank_init(dev, dev_priv->num_pipe); |
// if (ret) |
/drivers/video/drm/i915/i915_drv.c |
---|
57,6 → 57,8 |
"Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " |
"1=on, -1=force vga console preference [default])"); |
unsigned int i915_fbpercrtc __always_unused = 0; |
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); |
int i915_panel_ignore_lid __read_mostly = 1; |
module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); |
124,7 → 126,7 |
"WARNING: Disabling this can cause system wide hangs. " |
"(default: true)"); |
int i915_enable_ppgtt __read_mostly = false; |
int i915_enable_ppgtt __read_mostly = 0; |
module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600); |
MODULE_PARM_DESC(i915_enable_ppgtt, |
"Enable PPGTT (default: true)"); |
132,9 → 134,7 |
unsigned int i915_preliminary_hw_support __read_mostly = true; |
module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); |
MODULE_PARM_DESC(preliminary_hw_support, |
"Enable preliminary hardware support. " |
"Enable Haswell and ValleyView Support. " |
"(default: false)"); |
"Enable preliminary hardware support. (default: false)"); |
int i915_disable_power_well __read_mostly = 0; |
module_param_named(disable_power_well, i915_disable_power_well, int, 0600); |
152,23 → 152,31 |
.subdevice = PCI_ANY_ID, \ |
.driver_data = (unsigned long) info } |
#define INTEL_QUANTA_VGA_DEVICE(info) { \ |
.class = PCI_BASE_CLASS_DISPLAY << 16, \ |
.class_mask = 0xff0000, \ |
.vendor = 0x8086, \ |
.device = 0x16a, \ |
.subvendor = 0x152d, \ |
.subdevice = 0x8990, \ |
.driver_data = (unsigned long) info } |
static const struct intel_device_info intel_i915g_info = { |
.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, |
.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2, |
.has_overlay = 1, .overlay_needs_physical = 1, |
}; |
static const struct intel_device_info intel_i915gm_info = { |
.gen = 3, .is_mobile = 1, |
.gen = 3, .is_mobile = 1, .num_pipes = 2, |
.cursor_needs_physical = 1, |
.has_overlay = 1, .overlay_needs_physical = 1, |
.supports_tv = 1, |
}; |
static const struct intel_device_info intel_i945g_info = { |
.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, |
.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2, |
.has_overlay = 1, .overlay_needs_physical = 1, |
}; |
static const struct intel_device_info intel_i945gm_info = { |
.gen = 3, .is_i945gm = 1, .is_mobile = 1, |
.gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2, |
.has_hotplug = 1, .cursor_needs_physical = 1, |
.has_overlay = 1, .overlay_needs_physical = 1, |
.supports_tv = 1, |
175,13 → 183,13 |
}; |
static const struct intel_device_info intel_i965g_info = { |
.gen = 4, .is_broadwater = 1, |
.gen = 4, .is_broadwater = 1, .num_pipes = 2, |
.has_hotplug = 1, |
.has_overlay = 1, |
}; |
static const struct intel_device_info intel_i965gm_info = { |
.gen = 4, .is_crestline = 1, |
.gen = 4, .is_crestline = 1, .num_pipes = 2, |
.is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, |
.has_overlay = 1, |
.supports_tv = 1, |
188,19 → 196,19 |
}; |
static const struct intel_device_info intel_g33_info = { |
.gen = 3, .is_g33 = 1, |
.gen = 3, .is_g33 = 1, .num_pipes = 2, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_overlay = 1, |
}; |
static const struct intel_device_info intel_g45_info = { |
.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, |
.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2, |
.has_pipe_cxsr = 1, .has_hotplug = 1, |
.has_bsd_ring = 1, |
}; |
static const struct intel_device_info intel_gm45_info = { |
.gen = 4, .is_g4x = 1, |
.gen = 4, .is_g4x = 1, .num_pipes = 2, |
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, |
.has_pipe_cxsr = 1, .has_hotplug = 1, |
.supports_tv = 1, |
208,19 → 216,19 |
}; |
static const struct intel_device_info intel_pineview_info = { |
.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, |
.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_overlay = 1, |
}; |
static const struct intel_device_info intel_ironlake_d_info = { |
.gen = 5, |
.gen = 5, .num_pipes = 2, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_bsd_ring = 1, |
}; |
static const struct intel_device_info intel_ironlake_m_info = { |
.gen = 5, .is_mobile = 1, |
.gen = 5, .is_mobile = 1, .num_pipes = 2, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_fbc = 1, |
.has_bsd_ring = 1, |
227,7 → 235,7 |
}; |
static const struct intel_device_info intel_sandybridge_d_info = { |
.gen = 6, |
.gen = 6, .num_pipes = 2, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
236,7 → 244,7 |
}; |
static const struct intel_device_info intel_sandybridge_m_info = { |
.gen = 6, .is_mobile = 1, |
.gen = 6, .is_mobile = 1, .num_pipes = 2, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_fbc = 1, |
.has_bsd_ring = 1, |
245,61 → 253,57 |
.has_force_wake = 1, |
}; |
#define GEN7_FEATURES \ |
.gen = 7, .num_pipes = 3, \ |
.need_gfx_hws = 1, .has_hotplug = 1, \ |
.has_bsd_ring = 1, \ |
.has_blt_ring = 1, \ |
.has_llc = 1, \ |
.has_force_wake = 1 |
static const struct intel_device_info intel_ivybridge_d_info = { |
.is_ivybridge = 1, .gen = 7, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
.has_llc = 1, |
.has_force_wake = 1, |
GEN7_FEATURES, |
.is_ivybridge = 1, |
}; |
static const struct intel_device_info intel_ivybridge_m_info = { |
.is_ivybridge = 1, .gen = 7, .is_mobile = 1, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */ |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
.has_llc = 1, |
.has_force_wake = 1, |
GEN7_FEATURES, |
.is_ivybridge = 1, |
.is_mobile = 1, |
}; |
static const struct intel_device_info intel_ivybridge_q_info = { |
GEN7_FEATURES, |
.is_ivybridge = 1, |
.num_pipes = 0, /* legal, last one wins */ |
}; |
static const struct intel_device_info intel_valleyview_m_info = { |
.gen = 7, .is_mobile = 1, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_fbc = 0, |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
GEN7_FEATURES, |
.is_mobile = 1, |
.num_pipes = 2, |
.is_valleyview = 1, |
.display_mmio_offset = VLV_DISPLAY_BASE, |
.has_llc = 0, /* legal, last one wins */ |
}; |
static const struct intel_device_info intel_valleyview_d_info = { |
.gen = 7, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_fbc = 0, |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
GEN7_FEATURES, |
.num_pipes = 2, |
.is_valleyview = 1, |
.display_mmio_offset = VLV_DISPLAY_BASE, |
.has_llc = 0, /* legal, last one wins */ |
}; |
static const struct intel_device_info intel_haswell_d_info = { |
.is_haswell = 1, .gen = 7, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
.has_llc = 1, |
.has_force_wake = 1, |
GEN7_FEATURES, |
.is_haswell = 1, |
}; |
static const struct intel_device_info intel_haswell_m_info = { |
.is_haswell = 1, .gen = 7, .is_mobile = 1, |
.need_gfx_hws = 1, .has_hotplug = 1, |
.has_bsd_ring = 1, |
.has_blt_ring = 1, |
.has_llc = 1, |
.has_force_wake = 1, |
GEN7_FEATURES, |
.is_haswell = 1, |
.is_mobile = 1, |
}; |
static const struct pci_device_id pciidlist[] = { /* aka */ |
341,44 → 345,72 |
INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ |
INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ |
INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ |
INTEL_QUANTA_VGA_DEVICE(&intel_ivybridge_q_info), /* Quanta transcode */ |
INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ |
INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ |
INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ |
INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT2 desktop */ |
INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT3 desktop */ |
INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */ |
INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */ |
INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT2 server */ |
INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT3 server */ |
INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */ |
INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */ |
INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */ |
INTEL_VGA_DEVICE(0x040B, &intel_haswell_d_info), /* GT1 reserved */ |
INTEL_VGA_DEVICE(0x041B, &intel_haswell_d_info), /* GT2 reserved */ |
INTEL_VGA_DEVICE(0x042B, &intel_haswell_d_info), /* GT3 reserved */ |
INTEL_VGA_DEVICE(0x040E, &intel_haswell_d_info), /* GT1 reserved */ |
INTEL_VGA_DEVICE(0x041E, &intel_haswell_d_info), /* GT2 reserved */ |
INTEL_VGA_DEVICE(0x042E, &intel_haswell_d_info), /* GT3 reserved */ |
INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */ |
INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */ |
INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT2 desktop */ |
INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT3 desktop */ |
INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */ |
INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */ |
INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT2 server */ |
INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT3 server */ |
INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */ |
INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */ |
INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT2 mobile */ |
INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT3 mobile */ |
INTEL_VGA_DEVICE(0x0C0B, &intel_haswell_d_info), /* SDV GT1 reserved */ |
INTEL_VGA_DEVICE(0x0C1B, &intel_haswell_d_info), /* SDV GT2 reserved */ |
INTEL_VGA_DEVICE(0x0C2B, &intel_haswell_d_info), /* SDV GT3 reserved */ |
INTEL_VGA_DEVICE(0x0C0E, &intel_haswell_d_info), /* SDV GT1 reserved */ |
INTEL_VGA_DEVICE(0x0C1E, &intel_haswell_d_info), /* SDV GT2 reserved */ |
INTEL_VGA_DEVICE(0x0C2E, &intel_haswell_d_info), /* SDV GT3 reserved */ |
INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */ |
INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */ |
INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT2 desktop */ |
INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT3 desktop */ |
INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */ |
INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */ |
INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT2 server */ |
INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT3 server */ |
INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */ |
INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */ |
INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */ |
INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT3 mobile */ |
INTEL_VGA_DEVICE(0x0A0B, &intel_haswell_d_info), /* ULT GT1 reserved */ |
INTEL_VGA_DEVICE(0x0A1B, &intel_haswell_d_info), /* ULT GT2 reserved */ |
INTEL_VGA_DEVICE(0x0A2B, &intel_haswell_d_info), /* ULT GT3 reserved */ |
INTEL_VGA_DEVICE(0x0A0E, &intel_haswell_m_info), /* ULT GT1 reserved */ |
INTEL_VGA_DEVICE(0x0A1E, &intel_haswell_m_info), /* ULT GT2 reserved */ |
INTEL_VGA_DEVICE(0x0A2E, &intel_haswell_m_info), /* ULT GT3 reserved */ |
INTEL_VGA_DEVICE(0x0D02, &intel_haswell_d_info), /* CRW GT1 desktop */ |
INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT2 desktop */ |
INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */ |
INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT3 desktop */ |
INTEL_VGA_DEVICE(0x0D0A, &intel_haswell_d_info), /* CRW GT1 server */ |
INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT2 server */ |
INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */ |
INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT3 server */ |
INTEL_VGA_DEVICE(0x0D06, &intel_haswell_m_info), /* CRW GT1 mobile */ |
INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ |
INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ |
INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT3 mobile */ |
INTEL_VGA_DEVICE(0x0D0B, &intel_haswell_d_info), /* CRW GT1 reserved */ |
INTEL_VGA_DEVICE(0x0D1B, &intel_haswell_d_info), /* CRW GT2 reserved */ |
INTEL_VGA_DEVICE(0x0D2B, &intel_haswell_d_info), /* CRW GT3 reserved */ |
INTEL_VGA_DEVICE(0x0D0E, &intel_haswell_d_info), /* CRW GT1 reserved */ |
INTEL_VGA_DEVICE(0x0D1E, &intel_haswell_d_info), /* CRW GT2 reserved */ |
INTEL_VGA_DEVICE(0x0D2E, &intel_haswell_d_info), /* CRW GT3 reserved */ |
INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), |
INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info), |
INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info), |
INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info), |
INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), |
INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), |
{0, 0, 0} |
395,6 → 427,15 |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct pci_dev *pch; |
/* In all current cases, num_pipes is equivalent to the PCH_NOP setting |
* (which really amounts to a PCH but no South Display). |
*/ |
if (INTEL_INFO(dev)->num_pipes == 0) { |
dev_priv->pch_type = PCH_NOP; |
dev_priv->num_pch_pll = 0; |
return; |
} |
/* |
* The reason to probe ISA bridge instead of Dev31:Fun0 is to |
* make graphics device passthrough work easy for VMM, that only |
429,11 → 470,13 |
dev_priv->num_pch_pll = 0; |
DRM_DEBUG_KMS("Found LynxPoint PCH\n"); |
WARN_ON(!IS_HASWELL(dev)); |
WARN_ON(IS_ULT(dev)); |
} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { |
dev_priv->pch_type = PCH_LPT; |
dev_priv->num_pch_pll = 0; |
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); |
WARN_ON(!IS_HASWELL(dev)); |
WARN_ON(!IS_ULT(dev)); |
} |
BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); |
} |
726,6 → 769,11 |
return true; |
} |
/* We give fast paths for the really cool registers */ |
#define NEEDS_FORCE_WAKE(dev_priv, reg) \ |
((HAS_FORCE_WAKE((dev_priv)->dev)) && \ |
((reg) < 0x40000) && \ |
((reg) != FORCEWAKE)) |
static void |
ilk_dummy_write(struct drm_i915_private *dev_priv) |
{ |
735,6 → 783,27 |
I915_WRITE_NOTRACE(MI_MODE, 0); |
} |
static void |
hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) |
{ |
if (IS_HASWELL(dev_priv->dev) && |
(I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { |
DRM_ERROR("Unknown unclaimed register before writing to %x\n", |
reg); |
I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); |
} |
} |
static void |
hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) |
{ |
if (IS_HASWELL(dev_priv->dev) && |
(I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { |
DRM_ERROR("Unclaimed write to %x\n", reg); |
I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); |
} |
} |
#define __i915_read(x, y) \ |
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ |
u##x val = 0; \ |
770,18 → 839,12 |
} \ |
if (IS_GEN5(dev_priv->dev)) \ |
ilk_dummy_write(dev_priv); \ |
if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ |
DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ |
I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ |
} \ |
hsw_unclaimed_reg_clear(dev_priv, reg); \ |
write##y(val, dev_priv->regs + reg); \ |
if (unlikely(__fifo_ret)) { \ |
gen6_gt_check_fifodbg(dev_priv); \ |
} \ |
if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ |
DRM_ERROR("Unclaimed write to %x\n", reg); \ |
writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); \ |
} \ |
hsw_unclaimed_reg_check(dev_priv, reg); \ |
} |
__i915_write(8, b) |
__i915_write(16, w) |
/drivers/video/drm/i915/i915_drv.h |
---|
98,6 → 98,19 |
}; |
#define port_name(p) ((p) + 'A') |
enum hpd_pin { |
HPD_NONE = 0, |
HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ |
HPD_TV = HPD_NONE, /* TV is known to be unreliable */ |
HPD_CRT, |
HPD_SDVO_B, |
HPD_SDVO_C, |
HPD_PORT_B, |
HPD_PORT_C, |
HPD_PORT_D, |
HPD_NUM_PINS |
}; |
#define I915_GEM_GPU_DOMAINS \ |
(I915_GEM_DOMAIN_RENDER | \ |
I915_GEM_DOMAIN_SAMPLER | \ |
105,7 → 118,7 |
I915_GEM_DOMAIN_INSTRUCTION | \ |
I915_GEM_DOMAIN_VERTEX) |
#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) |
#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++) |
#define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ |
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ |
194,9 → 207,9 |
struct _drm_i915_sarea *sarea_priv; |
}; |
#define I915_FENCE_REG_NONE -1 |
#define I915_MAX_NUM_FENCES 16 |
/* 16 fences + sign bit for FENCE_REG_NONE */ |
#define I915_MAX_NUM_FENCE_BITS 5 |
#define I915_MAX_NUM_FENCES 32 |
/* 32 fences + sign bit for FENCE_REG_NONE */ |
#define I915_MAX_NUM_FENCE_BITS 6 |
struct drm_i915_fence_reg { |
struct list_head lru_list; |
255,7 → 268,7 |
int page_count; |
u32 gtt_offset; |
u32 *pages[0]; |
} *ringbuffer, *batchbuffer; |
} *ringbuffer, *batchbuffer, *ctx; |
struct drm_i915_error_request { |
long jiffies; |
u32 seqno; |
283,6 → 296,9 |
struct intel_display_error_state *display; |
}; |
struct intel_crtc_config; |
struct intel_crtc; |
struct drm_i915_display_funcs { |
bool (*fbc_enabled)(struct drm_device *dev); |
void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); |
295,9 → 311,11 |
void (*update_linetime_wm)(struct drm_device *dev, int pipe, |
struct drm_display_mode *mode); |
void (*modeset_global_resources)(struct drm_device *dev); |
/* Returns the active state of the crtc, and if the crtc is active, |
* fills out the pipe-config with the hw state. */ |
bool (*get_pipe_config)(struct intel_crtc *, |
struct intel_crtc_config *); |
int (*crtc_mode_set)(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, |
struct drm_framebuffer *old_fb); |
void (*crtc_enable)(struct drm_crtc *crtc); |
353,6 → 371,7 |
struct intel_device_info { |
u32 display_mmio_offset; |
u8 num_pipes:3; |
u8 gen; |
u8 is_mobile:1; |
u8 is_i85x:1; |
442,6 → 461,7 |
struct sg_table *st, |
unsigned int pg_start, |
enum i915_cache_level cache_level); |
int (*enable)(struct drm_device *dev); |
void (*cleanup)(struct i915_hw_ppgtt *ppgtt); |
}; |
472,6 → 492,7 |
PCH_IBX, /* Ibexpeak PCH */ |
PCH_CPT, /* Cougarpoint PCH */ |
PCH_LPT, /* Lynxpoint PCH */ |
PCH_NOP, |
}; |
enum intel_sbi_destination { |
659,6 → 680,7 |
u8 cur_delay; |
u8 min_delay; |
u8 max_delay; |
u8 hw_max; |
struct delayed_work delayed_resume_work; |
915,16 → 937,23 |
struct mutex dpio_lock; |
/** Cached value of IMR to avoid reads in updating the bitfield */ |
u32 pipestat[2]; |
u32 irq_mask; |
u32 gt_irq_mask; |
u32 hotplug_supported_mask; |
struct work_struct hotplug_work; |
bool enable_hotplug_processing; |
struct { |
unsigned long hpd_last_jiffies; |
int hpd_cnt; |
enum { |
HPD_ENABLED = 0, |
HPD_DISABLED = 1, |
HPD_MARK_DISABLED = 2 |
} hpd_mark; |
} hpd_stats[HPD_NUM_PINS]; |
int num_pipe; |
int num_pch_pll; |
int num_plane; |
unsigned long cfb_size; |
unsigned int cfb_fb; |
938,9 → 967,14 |
struct intel_overlay *overlay; |
unsigned int sprite_scaling_enabled; |
/* backlight */ |
struct { |
int level; |
bool enabled; |
struct backlight_device *device; |
} backlight; |
/* LVDS info */ |
int backlight_level; /* restore backlight to this value */ |
bool backlight_enabled; |
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ |
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ |
951,6 → 985,7 |
unsigned int int_crt_support:1; |
unsigned int lvds_use_ssc:1; |
unsigned int display_clock_mode:1; |
unsigned int fdi_rx_polarity_inverted:1; |
int lvds_ssc_freq; |
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ |
struct { |
1042,8 → 1077,6 |
*/ |
struct work_struct console_resume_work; |
// struct backlight_device *backlight; |
struct drm_property *broadcast_rgb_property; |
struct drm_property *force_audio_property; |
1350,6 → 1383,7 |
#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) |
#define HAS_DDI(dev) (IS_HASWELL(dev)) |
#define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) |
#define INTEL_PCH_DEVICE_ID_MASK 0xff00 |
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 |
1362,6 → 1396,7 |
#define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) |
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) |
#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) |
#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP) |
#define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE) |
#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) |
1534,18 → 1569,13 |
int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); |
static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) |
{ |
struct scatterlist *sg = obj->pages->sgl; |
int nents = obj->pages->nents; |
while (nents > SG_MAX_SINGLE_ALLOC) { |
if (n < SG_MAX_SINGLE_ALLOC - 1) |
break; |
struct sg_page_iter sg_iter; |
sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1); |
n -= SG_MAX_SINGLE_ALLOC - 1; |
nents -= SG_MAX_SINGLE_ALLOC - 1; |
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n) |
return sg_page_iter_page(&sg_iter); |
return NULL; |
} |
return sg_page(sg+n); |
} |
static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) |
{ |
BUG_ON(obj->pages == NULL); |
1629,7 → 1659,6 |
int __must_check i915_gem_init_hw(struct drm_device *dev); |
void i915_gem_l3_remap(struct drm_device *dev); |
void i915_gem_init_swizzling(struct drm_device *dev); |
void i915_gem_init_ppgtt(struct drm_device *dev); |
void i915_gem_cleanup_ringbuffer(struct drm_device *dev); |
int __must_check i915_gpu_idle(struct drm_device *dev); |
int __must_check i915_gem_idle(struct drm_device *dev); |
1670,6 → 1699,8 |
struct dma_buf *i915_gem_prime_export(struct drm_device *dev, |
struct drm_gem_object *gem_obj, int flags); |
void i915_gem_restore_fences(struct drm_device *dev); |
/* i915_gem_context.c */ |
void i915_gem_context_init(struct drm_device *dev); |
void i915_gem_context_fini(struct drm_device *dev); |
1721,6 → 1752,11 |
void i915_gem_cleanup_stolen(struct drm_device *dev); |
struct drm_i915_gem_object * |
i915_gem_object_create_stolen(struct drm_device *dev, u32 size); |
struct drm_i915_gem_object * |
i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, |
u32 stolen_offset, |
u32 gtt_offset, |
u32 size); |
void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); |
/* i915_gem_tiling.c */ |
1851,6 → 1887,8 |
int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); |
int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); |
int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); |
int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); |
#define __i915_read(x, y) \ |
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); |
1904,6 → 1942,27 |
return VGACNTRL; |
} |
static inline void __user *to_user_ptr(u64 address) |
{ |
return (void __user *)(uintptr_t)address; |
} |
static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m) |
{ |
unsigned long j = msecs_to_jiffies(m); |
return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); |
} |
static inline unsigned long |
timespec_to_jiffies_timeout(const struct timespec *value) |
{ |
unsigned long j = timespec_to_jiffies(value); |
return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); |
} |
typedef struct |
{ |
int width; |
/drivers/video/drm/i915/i915_gem.c |
---|
33,6 → 33,7 |
#include <linux/shmem_fs.h> |
#include <linux/slab.h> |
//#include <linux/swap.h> |
#include <linux/scatterlist.h> |
#include <linux/pci.h> |
extern int x86_clflush_size; |
447,10 → 448,9 |
int obj_do_bit17_swizzling, page_do_bit17_swizzling; |
int prefaulted = 0; |
int needs_clflush = 0; |
struct scatterlist *sg; |
int i; |
struct sg_page_iter sg_iter; |
user_data = (char __user *) (uintptr_t) args->data_ptr; |
user_data = to_user_ptr(args->data_ptr); |
remain = args->size; |
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); |
477,12 → 477,10 |
offset = args->offset; |
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { |
struct page *page; |
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, |
offset >> PAGE_SHIFT) { |
struct page *page = sg_page_iter_page(&sg_iter); |
if (i < offset >> PAGE_SHIFT) |
continue; |
if (remain <= 0) |
break; |
496,7 → 494,6 |
if ((shmem_page_offset + page_length) > PAGE_SIZE) |
page_length = PAGE_SIZE - shmem_page_offset; |
page = sg_page(sg); |
page_do_bit17_swizzling = obj_do_bit17_swizzling && |
(page_to_phys(page) & (1 << 17)) != 0; |
558,7 → 555,7 |
return 0; |
if (!access_ok(VERIFY_WRITE, |
(char __user *)(uintptr_t)args->data_ptr, |
to_user_ptr(args->data_ptr), |
args->size)) |
return -EFAULT; |
777,10 → 774,9 |
int hit_slowpath = 0; |
int needs_clflush_after = 0; |
int needs_clflush_before = 0; |
int i; |
struct scatterlist *sg; |
struct sg_page_iter sg_iter; |
user_data = (char __user *) (uintptr_t) args->data_ptr; |
user_data = to_user_ptr(args->data_ptr); |
remain = args->size; |
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); |
813,13 → 809,11 |
offset = args->offset; |
obj->dirty = 1; |
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { |
struct page *page; |
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, |
offset >> PAGE_SHIFT) { |
struct page *page = sg_page_iter_page(&sg_iter); |
int partial_cacheline_write; |
if (i < offset >> PAGE_SHIFT) |
continue; |
if (remain <= 0) |
break; |
841,7 → 835,6 |
((shmem_page_offset | page_length) |
& (x86_clflush_size - 1)); |
page = sg_page(sg); |
page_do_bit17_swizzling = obj_do_bit17_swizzling && |
(page_to_phys(page) & (1 << 17)) != 0; |
1102,8 → 1095,6 |
case -ERESTARTSYS: /* Signal */ |
return (int)end; |
case 0: /* Timeout */ |
if (timeout) |
set_normalized_timespec(timeout, 0, 0); |
return -ETIME; |
default: /* Completed */ |
WARN_ON(end < 0); /* We're not aware of other errors */ |
1590,9 → 1581,8 |
static void |
i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) |
{ |
int page_count = obj->base.size / PAGE_SIZE; |
struct scatterlist *sg; |
int ret, i; |
struct sg_page_iter sg_iter; |
int ret; |
BUG_ON(obj->madv == __I915_MADV_PURGED); |
1609,8 → 1599,8 |
if (obj->madv == I915_MADV_DONTNEED) |
obj->dirty = 0; |
for_each_sg(obj->pages->sgl, sg, page_count, i) { |
struct page *page = sg_page(sg); |
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { |
struct page *page = sg_page_iter_page(&sg_iter); |
page_cache_release(page); |
} |
1661,10 → 1651,11 |
{ |
struct drm_i915_private *dev_priv = obj->base.dev->dev_private; |
int page_count, i; |
struct address_space *mapping; |
struct sg_table *st; |
struct scatterlist *sg; |
struct sg_page_iter sg_iter; |
struct page *page; |
unsigned long last_pfn = 0; /* suppress gcc warning */ |
gfp_t gfp; |
/* Assert that the object is not currently in any GPU domain. As it |
1682,6 → 1673,7 |
if (sg_alloc_table(st, page_count, GFP_KERNEL)) { |
sg_free_table(st); |
kfree(st); |
FAIL(); |
return -ENOMEM; |
} |
1690,7 → 1682,9 |
* |
* Fail silently without starting the shrinker |
*/ |
for_each_sg(st->sgl, sg, page_count, i) { |
sg = st->sgl; |
st->nents = 0; |
for (i = 0; i < page_count; i++) { |
page = shmem_read_mapping_page_gfp(obj->base.filp, i, gfp); |
if (IS_ERR(page)) { |
dbgprintf("%s invalid page %p\n", __FUNCTION__, page); |
1697,20 → 1691,30 |
goto err_pages; |
} |
if (!i || page_to_pfn(page) != last_pfn + 1) { |
if (i) |
sg = sg_next(sg); |
st->nents++; |
sg_set_page(sg, page, PAGE_SIZE, 0); |
} else { |
sg->length += PAGE_SIZE; |
} |
last_pfn = page_to_pfn(page); |
} |
sg_mark_end(sg); |
obj->pages = st; |
// DRM_DEBUG_KMS("%s alloc %d pages\n", __FUNCTION__, page_count); |
return 0; |
err_pages: |
for_each_sg(st->sgl, sg, i, page_count) |
page_cache_release(sg_page(sg)); |
sg_mark_end(sg); |
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) |
page_cache_release(sg_page_iter_page(&sg_iter)); |
sg_free_table(st); |
kfree(st); |
FAIL(); |
return PTR_ERR(page); |
} |
1997,7 → 2001,7 |
} |
} |
static void i915_gem_reset_fences(struct drm_device *dev) |
void i915_gem_restore_fences(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int i; |
2004,18 → 2008,8 |
for (i = 0; i < dev_priv->num_fence_regs; i++) { |
struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; |
i915_gem_write_fence(dev, i, NULL); |
if (reg->obj) |
i915_gem_object_fence_lost(reg->obj); |
reg->pin_count = 0; |
reg->obj = NULL; |
INIT_LIST_HEAD(®->lru_list); |
i915_gem_write_fence(dev, i, reg->obj); |
} |
INIT_LIST_HEAD(&dev_priv->mm.fence_list); |
} |
void i915_gem_reset(struct drm_device *dev) |
2038,8 → 2032,7 |
obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; |
} |
/* The fence registers are invalidated so clear them out */ |
i915_gem_reset_fences(dev); |
i915_gem_restore_fences(dev); |
} |
/** |
2510,17 → 2503,36 |
return fence - dev_priv->fence_regs; |
} |
static void i915_gem_write_fence__ipi(void *data) |
{ |
asm volatile("wbinvd"); |
} |
static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, |
struct drm_i915_fence_reg *fence, |
bool enable) |
{ |
struct drm_i915_private *dev_priv = obj->base.dev->dev_private; |
int reg = fence_number(dev_priv, fence); |
struct drm_device *dev = obj->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int fence_reg = fence_number(dev_priv, fence); |
i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); |
/* In order to fully serialize access to the fenced region and |
* the update to the fence register we need to take extreme |
* measures on SNB+. In theory, the write to the fence register |
* flushes all memory transactions before, and coupled with the |
* mb() placed around the register write we serialise all memory |
* operations with respect to the changes in the tiler. Yet, on |
* SNB+ we need to take a step further and emit an explicit wbinvd() |
* on each processor in order to manually flush all memory |
* transactions before updating the fence register. |
*/ |
if (HAS_LLC(obj->base.dev)) |
on_each_cpu(i915_gem_write_fence__ipi, NULL, 1); |
i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); |
if (enable) { |
obj->fence_reg = reg; |
obj->fence_reg = fence_reg; |
fence->obj = obj; |
list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); |
} else { |
2549,6 → 2561,7 |
i915_gem_object_put_fence(struct drm_i915_gem_object *obj) |
{ |
struct drm_i915_private *dev_priv = obj->base.dev->dev_private; |
struct drm_i915_fence_reg *fence; |
int ret; |
ret = i915_gem_object_wait_fence(obj); |
2558,10 → 2571,10 |
if (obj->fence_reg == I915_FENCE_REG_NONE) |
return 0; |
i915_gem_object_update_fence(obj, |
&dev_priv->fence_regs[obj->fence_reg], |
false); |
fence = &dev_priv->fence_regs[obj->fence_reg]; |
i915_gem_object_fence_lost(obj); |
i915_gem_object_update_fence(obj, fence, false); |
return 0; |
} |
2774,6 → 2787,7 |
if (obj->base.size > |
(map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { |
DRM_ERROR("Attempting to bind an object larger than the aperture\n"); |
FAIL(); |
return -E2BIG; |
} |
3633,12 → 3647,18 |
struct address_space *mapping; |
gfp_t mask; |
obj = i915_gem_object_alloc(dev); |
obj = kzalloc(sizeof(*obj), GFP_KERNEL); |
if (obj == NULL) |
{ |
FAIL(); |
return NULL; |
}; |
if (drm_gem_object_init(dev, &obj->base, size) != 0) { |
kfree(obj); |
FAIL(); |
return NULL; |
} |
3746,8 → 3766,6 |
if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
i915_gem_evict_everything(dev); |
i915_gem_reset_fences(dev); |
/* Hack! Don't let anybody do execbuf while we don't control the chip. |
* We need to replace this with a semaphore, or something. |
* And not confound mm.suspended! |
3887,6 → 3905,12 |
if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) |
I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); |
if (HAS_PCH_NOP(dev)) { |
u32 temp = I915_READ(GEN7_MSG_CTL); |
temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); |
I915_WRITE(GEN7_MSG_CTL, temp); |
} |
i915_gem_l3_remap(dev); |
i915_gem_init_swizzling(dev); |
3900,7 → 3924,13 |
* contexts before PPGTT. |
*/ |
i915_gem_context_init(dev); |
i915_gem_init_ppgtt(dev); |
if (dev_priv->mm.aliasing_ppgtt) { |
ret = dev_priv->mm.aliasing_ppgtt->enable(dev); |
if (ret) { |
i915_gem_cleanup_aliasing_ppgtt(dev); |
DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); |
} |
} |
return 0; |
} |
3913,7 → 3943,16 |
int ret; |
mutex_lock(&dev->struct_mutex); |
if (IS_VALLEYVIEW(dev)) { |
/* VLVA0 (potential hack), BIOS isn't actually waking us */ |
I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); |
if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) |
DRM_DEBUG_DRIVER("allow wake ack timed out\n"); |
} |
i915_gem_init_global_gtt(dev); |
ret = i915_gem_init_hw(dev); |
mutex_unlock(&dev->struct_mutex); |
if (ret) { |
3921,6 → 3960,7 |
return ret; |
} |
return 0; |
} |
4038,13 → 4078,16 |
dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL; |
if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) |
if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) |
dev_priv->num_fence_regs = 32; |
else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) |
dev_priv->num_fence_regs = 16; |
else |
dev_priv->num_fence_regs = 8; |
/* Initialize fence registers to zero */ |
i915_gem_reset_fences(dev); |
INIT_LIST_HEAD(&dev_priv->mm.fence_list); |
i915_gem_restore_fences(dev); |
i915_gem_detect_bit_6_swizzle(dev); |
/drivers/video/drm/i915/i915_gem_context.c |
---|
95,8 → 95,6 |
*/ |
#define CONTEXT_ALIGN (64<<10) |
#if 0 |
static struct i915_hw_context * |
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); |
static int do_switch(struct i915_hw_context *to); |
154,6 → 152,13 |
return ERR_PTR(-ENOMEM); |
} |
if (INTEL_INFO(dev)->gen >= 7) { |
ret = i915_gem_object_set_cache_level(ctx->obj, |
I915_CACHE_LLC_MLC); |
if (ret) |
goto err_out; |
} |
/* The ring associated with the context object is handled by the normal |
* object tracking code. We give an initial ring value simple to pass an |
* assertion in the context switch code. |
224,13 → 229,11 |
do_destroy(ctx); |
return ret; |
} |
#endif |
void i915_gem_context_init(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
#if 0 |
if (!HAS_HW_CONTEXTS(dev)) { |
dev_priv->hw_contexts_disabled = true; |
return; |
254,11 → 257,8 |
} |
DRM_DEBUG_DRIVER("HW context support initialized\n"); |
#endif |
} |
#if 0 |
void i915_gem_context_fini(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
269,7 → 269,7 |
/* The only known way to stop the gpu from accessing the hw context is |
* to reset it. Do this as the very last operation to avoid confusing |
* other code, leading to spurious errors. */ |
intel_gpu_reset(dev); |
// intel_gpu_reset(dev); |
i915_gem_object_unpin(dev_priv->ring[RCS].default_context->obj); |
292,7 → 292,7 |
struct drm_i915_file_private *file_priv = file->driver_priv; |
mutex_lock(&dev->struct_mutex); |
idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); |
// idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); |
idr_destroy(&file_priv->context_idr); |
mutex_unlock(&dev->struct_mutex); |
} |
420,7 → 420,6 |
return 0; |
} |
#endif |
/** |
* i915_switch_context() - perform a GPU context switch. |
445,7 → 444,6 |
if (dev_priv->hw_contexts_disabled) |
return 0; |
#if 0 |
if (ring != &dev_priv->ring[RCS]) |
return 0; |
461,9 → 459,6 |
} |
return do_switch(to); |
#endif |
return 0; |
} |
#if 0 |
/drivers/video/drm/i915/i915_gem_execbuffer.c |
---|
26,8 → 26,6 |
* |
*/ |
#define iowrite32(v, addr) writel((v), (addr)) |
#include <drm/drmP.h> |
#include <drm/i915_drm.h> |
#include "i915_drv.h" |
384,8 → 382,7 |
} |
static int |
i915_gem_execbuffer_relocate(struct drm_device *dev, |
struct eb_objects *eb) |
i915_gem_execbuffer_relocate(struct eb_objects *eb) |
{ |
struct drm_i915_gem_object *obj; |
int ret = 0; |
508,7 → 505,6 |
static int |
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, |
struct drm_file *file, |
struct list_head *objects, |
bool *need_relocs) |
{ |
701,7 → 697,7 |
goto err; |
need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; |
ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); |
ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); |
if (ret) |
goto err; |
774,7 → 770,7 |
int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); |
for (i = 0; i < count; i++) { |
char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; |
char __user *ptr = to_user_ptr(exec[i].relocs_ptr); |
int length; /* limited by fault_in_pages_readable() */ |
if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) |
790,7 → 786,11 |
length = exec[i].relocation_count * |
sizeof(struct drm_i915_gem_relocation_entry); |
/* we may also need to update the presumed offsets */ |
/* |
* We must check that the entire relocation array is safe |
* to read, but since we may need to update the presumed |
* offsets during execution, check for full write access. |
*/ |
// if (!access_ok(VERIFY_WRITE, ptr, length)) |
// return -EFAULT; |
992,8 → 992,7 |
} |
if (copy_from_user(cliprects, |
(struct drm_clip_rect __user *)(uintptr_t) |
args->cliprects_ptr, |
to_user_ptr(args->cliprects_ptr), |
sizeof(*cliprects)*args->num_cliprects)) { |
ret = -EFAULT; |
goto pre_mutex_err; |
1029,13 → 1028,13 |
/* Move the objects en-masse into the GTT, evicting if necessary. */ |
need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; |
ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); |
ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); |
if (ret) |
goto err; |
/* The objects are in their final locations, apply the relocations. */ |
if (need_relocs) |
ret = i915_gem_execbuffer_relocate(dev, eb); |
ret = i915_gem_execbuffer_relocate(eb); |
if (ret) { |
if (ret == -EFAULT) { |
ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, |
/drivers/video/drm/i915/i915_gem_gtt.c |
---|
22,7 → 22,6 |
* |
*/ |
#define iowrite32(v, addr) writel((v), (addr)) |
#define AGP_NORMAL_MEMORY 0 |
36,7 → 35,7 |
#include "i915_trace.h" |
#include "intel_drv.h" |
typedef uint32_t gtt_pte_t; |
typedef uint32_t gen6_gtt_pte_t; |
/* PPGTT stuff */ |
#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) |
52,11 → 51,11 |
#define GEN6_PTE_CACHE_LLC_MLC (3 << 1) |
#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) |
static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, |
static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, |
dma_addr_t addr, |
enum i915_cache_level level) |
{ |
gtt_pte_t pte = GEN6_PTE_VALID; |
gen6_gtt_pte_t pte = GEN6_PTE_VALID; |
pte |= GEN6_PTE_ADDR_ENCODE(addr); |
switch (level) { |
80,18 → 79,85 |
BUG(); |
} |
return pte; |
} |
static int gen6_ppgtt_enable(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
uint32_t pd_offset; |
struct intel_ring_buffer *ring; |
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; |
gen6_gtt_pte_t __iomem *pd_addr; |
uint32_t pd_entry; |
int i; |
pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm + |
ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); |
for (i = 0; i < ppgtt->num_pd_entries; i++) { |
dma_addr_t pt_addr; |
pt_addr = ppgtt->pt_dma_addr[i]; |
pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); |
pd_entry |= GEN6_PDE_VALID; |
writel(pd_entry, pd_addr + i); |
} |
readl(pd_addr); |
pd_offset = ppgtt->pd_offset; |
pd_offset /= 64; /* in cachelines, */ |
pd_offset <<= 16; |
if (INTEL_INFO(dev)->gen == 6) { |
uint32_t ecochk, gab_ctl, ecobits; |
ecobits = I915_READ(GAC_ECO_BITS); |
I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | |
ECOBITS_PPGTT_CACHE64B); |
gab_ctl = I915_READ(GAB_CTL); |
I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); |
ecochk = I915_READ(GAM_ECOCHK); |
I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | |
ECOCHK_PPGTT_CACHE64B); |
I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); |
} else if (INTEL_INFO(dev)->gen >= 7) { |
uint32_t ecochk, ecobits; |
ecobits = I915_READ(GAC_ECO_BITS); |
I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); |
ecochk = I915_READ(GAM_ECOCHK); |
if (IS_HASWELL(dev)) { |
ecochk |= ECOCHK_PPGTT_WB_HSW; |
} else { |
ecochk |= ECOCHK_PPGTT_LLC_IVB; |
ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; |
} |
I915_WRITE(GAM_ECOCHK, ecochk); |
/* GFX_MODE is per-ring on gen7+ */ |
} |
for_each_ring(ring, dev_priv, i) { |
if (INTEL_INFO(dev)->gen >= 7) |
I915_WRITE(RING_MODE_GEN7(ring), |
_MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); |
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); |
I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); |
} |
return 0; |
} |
/* PPGTT support for Sandybdrige/Gen6 and later */ |
static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, |
unsigned first_entry, |
unsigned num_entries) |
{ |
gtt_pte_t *pt_vaddr; |
gtt_pte_t scratch_pte; |
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; |
gen6_gtt_pte_t *pt_vaddr, scratch_pte; |
unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; |
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; |
unsigned last_pte, i; |
109,7 → 175,7 |
if (last_pte > I915_PPGTT_PT_ENTRIES) |
last_pte = I915_PPGTT_PT_ENTRIES; |
MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pd]), 3); |
MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pt]), 3); |
for (i = first_pte; i < last_pte; i++) |
pt_vaddr[i] = scratch_pte; |
116,7 → 182,7 |
num_entries -= last_pte - first_pte; |
first_pte = 0; |
act_pd++; |
act_pt++; |
}; |
FreeKernelSpace(pt_vaddr); |
127,18 → 193,12 |
unsigned first_entry, |
enum i915_cache_level cache_level) |
{ |
gtt_pte_t *pt_vaddr; |
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; |
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; |
unsigned i, j, m, segment_len; |
gen6_gtt_pte_t *pt_vaddr; |
unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; |
unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; |
struct sg_page_iter sg_iter; |
dma_addr_t page_addr; |
struct scatterlist *sg; |
/* init sg walking */ |
sg = pages->sgl; |
i = 0; |
segment_len = sg_dma_len(sg) >> PAGE_SHIFT; |
m = 0; |
pt_vaddr = AllocKernelSpace(4096); |
145,28 → 205,20 |
if(pt_vaddr == NULL) |
return; |
while (i < pages->nents) { |
MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pd]), 3); |
MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pt]), 3); |
for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { |
dma_addr_t page_addr; |
for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { |
page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); |
pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr, |
page_addr = sg_page_iter_dma_address(&sg_iter); |
pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, |
cache_level); |
if (++act_pte == I915_PPGTT_PT_ENTRIES) { |
act_pt++; |
MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pt]), 3); |
act_pte = 0; |
/* grab the next page */ |
if (++m == segment_len) { |
if (++i == pages->nents) |
break; |
sg = sg_next(sg); |
segment_len = sg_dma_len(sg) >> PAGE_SHIFT; |
m = 0; |
} |
} |
first_pte = 0; |
act_pd++; |
} |
FreeKernelSpace(pt_vaddr); |
} |
199,10 → 251,10 |
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 |
* entries. For aliasing ppgtt support we just steal them at the end for |
* now. */ |
first_pd_entry_in_global_pt = |
gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; |
first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt); |
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; |
ppgtt->enable = gen6_ppgtt_enable; |
ppgtt->clear_range = gen6_ppgtt_clear_range; |
ppgtt->insert_entries = gen6_ppgtt_insert_entries; |
ppgtt->cleanup = gen6_ppgtt_cleanup; |
231,12 → 283,10 |
ppgtt->pt_dma_addr[i] = pt_addr; |
} |
ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; |
ppgtt->clear_range(ppgtt, 0, |
ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); |
ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); |
ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); |
return 0; |
268,8 → 318,13 |
return -ENOMEM; |
ppgtt->dev = dev; |
ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; |
if (INTEL_INFO(dev)->gen < 8) |
ret = gen6_ppgtt_init(ppgtt); |
else |
BUG(); |
if (ret) |
kfree(ppgtt); |
else |
287,6 → 342,7 |
return; |
ppgtt->cleanup(ppgtt); |
dev_priv->mm.aliasing_ppgtt = NULL; |
} |
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, |
306,64 → 362,6 |
obj->base.size >> PAGE_SHIFT); |
} |
void i915_gem_init_ppgtt(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
uint32_t pd_offset; |
struct intel_ring_buffer *ring; |
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; |
gtt_pte_t __iomem *pd_addr; |
uint32_t pd_entry; |
int i; |
if (!dev_priv->mm.aliasing_ppgtt) |
return; |
pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); |
for (i = 0; i < ppgtt->num_pd_entries; i++) { |
dma_addr_t pt_addr; |
pt_addr = ppgtt->pt_dma_addr[i]; |
pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); |
pd_entry |= GEN6_PDE_VALID; |
writel(pd_entry, pd_addr + i); |
} |
readl(pd_addr); |
pd_offset = ppgtt->pd_offset; |
pd_offset /= 64; /* in cachelines, */ |
pd_offset <<= 16; |
if (INTEL_INFO(dev)->gen == 6) { |
uint32_t ecochk, gab_ctl, ecobits; |
ecobits = I915_READ(GAC_ECO_BITS); |
I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); |
gab_ctl = I915_READ(GAB_CTL); |
I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); |
ecochk = I915_READ(GAM_ECOCHK); |
I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | |
ECOCHK_PPGTT_CACHE64B); |
I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); |
} else if (INTEL_INFO(dev)->gen >= 7) { |
I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); |
/* GFX_MODE is per-ring on gen7+ */ |
} |
for_each_ring(ring, dev_priv, i) { |
if (INTEL_INFO(dev)->gen >= 7) |
I915_WRITE(RING_MODE_GEN7(ring), |
_MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); |
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); |
I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); |
} |
} |
extern int intel_iommu_gfx_mapped; |
/* Certain Gen5 chipsets require require idling the GPU before |
* unmapping anything from the GTT when VT-d is enabled. |
444,22 → 442,17 |
enum i915_cache_level level) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct scatterlist *sg = st->sgl; |
gtt_pte_t __iomem *gtt_entries = |
(gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; |
int unused, i = 0; |
unsigned int len, m = 0; |
gen6_gtt_pte_t __iomem *gtt_entries = |
(gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; |
int i = 0; |
struct sg_page_iter sg_iter; |
dma_addr_t addr; |
for_each_sg(st->sgl, sg, st->nents, unused) { |
len = sg_dma_len(sg) >> PAGE_SHIFT; |
for (m = 0; m < len; m++) { |
addr = sg_dma_address(sg) + (m << PAGE_SHIFT); |
iowrite32(gen6_pte_encode(dev, addr, level), |
>t_entries[i]); |
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { |
addr = sg_page_iter_dma_address(&sg_iter); |
iowrite32(gen6_pte_encode(dev, addr, level), >t_entries[i]); |
i++; |
} |
} |
/* XXX: This serves as a posting read to make sure that the PTE has |
* actually been updated. There is some concern that even though |
484,14 → 477,15 |
unsigned int num_entries) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
gtt_pte_t scratch_pte; |
gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; |
gen6_gtt_pte_t scratch_pte, __iomem *gtt_base = |
(gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; |
const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; |
int i; |
if (WARN(num_entries > max_entries, |
"First entry = %d; Num entries = %d (max=%d)\n", |
first_entry, num_entries, max_entries)) |
// if (WARN(num_entries > max_entries, |
// "First entry = %d; Num entries = %d (max=%d)\n", |
// first_entry, num_entries, max_entries)) |
if (num_entries > max_entries) |
num_entries = max_entries; |
scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma, |
657,13 → 651,18 |
gtt_size = dev_priv->gtt.total; |
mappable_size = dev_priv->gtt.mappable_end; |
#if 0 |
if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { |
int ret; |
if (INTEL_INFO(dev)->gen <= 7) { |
/* PPGTT pdes are stolen from global gtt ptes, so shrink the |
* aperture accordingly when using aliasing ppgtt. */ |
gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; |
gtt_size -= LFB_SIZE; |
} |
// gtt_size -= LFB_SIZE; |
i915_gem_setup_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size); |
ret = i915_gem_init_aliasing_ppgtt(dev); |
674,6 → 673,8 |
drm_mm_takedown(&dev_priv->mm.gtt_space); |
gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE; |
} |
#endif |
i915_gem_setup_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size); |
} |
727,15 → 728,6 |
return snb_gmch_ctl << 25; /* 32 MB units */ |
} |
static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl) |
{ |
static const int stolen_decoder[] = { |
0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352}; |
snb_gmch_ctl >>= IVB_GMCH_GMS_SHIFT; |
snb_gmch_ctl &= IVB_GMCH_GMS_MASK; |
return stolen_decoder[snb_gmch_ctl] << 20; |
} |
static int gen6_gmch_probe(struct drm_device *dev, |
size_t *gtt_total, |
size_t *stolen, |
765,15 → 757,13 |
pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); |
gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); |
if (IS_GEN7(dev)) |
*stolen = gen7_get_stolen_size(snb_gmch_ctl); |
else |
*stolen = gen6_get_stolen_size(snb_gmch_ctl); |
*gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT; |
*gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; |
/* For Modern GENs the PTEs and register space are split in the BAR */ |
gtt_bus_addr = pci_resource_start(dev->pdev, 0) + |
(pci_resource_len(dev->pdev, 0) / 2); |
/* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ |
gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); |
dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); |
if (!dev_priv->gtt.gsm) { |
DRM_ERROR("Failed to map the gtt page table\n"); |
830,7 → 820,6 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct i915_gtt *gtt = &dev_priv->gtt; |
unsigned long gtt_size; |
int ret; |
if (INTEL_INFO(dev)->gen <= 5) { |
848,8 → 837,6 |
if (ret) |
return ret; |
gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); |
/* GMADR is the PCI mmio aperture into the global GTT. */ |
DRM_INFO("Memory usable by graphics device = %zdM\n", |
dev_priv->gtt.total >> 20); |
997,3 → 984,40 |
sg_mark_end(&sgl[nents - 1]); |
} |
void __sg_page_iter_start(struct sg_page_iter *piter, |
struct scatterlist *sglist, unsigned int nents, |
unsigned long pgoffset) |
{ |
piter->__pg_advance = 0; |
piter->__nents = nents; |
piter->sg = sglist; |
piter->sg_pgoffset = pgoffset; |
} |
static int sg_page_count(struct scatterlist *sg) |
{ |
return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT; |
} |
bool __sg_page_iter_next(struct sg_page_iter *piter) |
{ |
if (!piter->__nents || !piter->sg) |
return false; |
piter->sg_pgoffset += piter->__pg_advance; |
piter->__pg_advance = 1; |
while (piter->sg_pgoffset >= sg_page_count(piter->sg)) { |
piter->sg_pgoffset -= sg_page_count(piter->sg); |
piter->sg = sg_next(piter->sg); |
if (!--piter->__nents || !piter->sg) |
return false; |
} |
return true; |
} |
EXPORT_SYMBOL(__sg_page_iter_next); |
/drivers/video/drm/i915/i915_gem_tiling.c |
---|
236,9 → 236,12 |
tile_width = 512; |
/* check maximum stride & object size */ |
if (INTEL_INFO(dev)->gen >= 4) { |
/* i965 stores the end address of the gtt mapping in the fence |
/* i965+ stores the end address of the gtt mapping in the fence |
* reg, so dont bother to check the size */ |
if (INTEL_INFO(dev)->gen >= 7) { |
if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL) |
return false; |
} else if (INTEL_INFO(dev)->gen >= 4) { |
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) |
return false; |
} else { |
254,6 → 257,9 |
} |
} |
if (stride < tile_width) |
return false; |
/* 965+ just needs multiples of tile width */ |
if (INTEL_INFO(dev)->gen >= 4) { |
if (stride & (tile_width - 1)) |
262,9 → 268,6 |
} |
/* Pre-965 needs power of two tile widths */ |
if (stride < tile_width) |
return false; |
if (stride & (stride - 1)) |
return false; |
492,15 → 495,15 |
void |
i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) |
{ |
struct scatterlist *sg; |
int page_count = obj->base.size >> PAGE_SHIFT; |
struct sg_page_iter sg_iter; |
int i; |
if (obj->bit_17 == NULL) |
return; |
for_each_sg(obj->pages->sgl, sg, page_count, i) { |
struct page *page = sg_page(sg); |
i = 0; |
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { |
struct page *page = sg_page_iter_page(&sg_iter); |
char new_bit_17 = page_to_phys(page) >> 17; |
if ((new_bit_17 & 0x1) != |
(test_bit(i, obj->bit_17) != 0)) { |
507,6 → 510,7 |
i915_gem_swizzle_page(page); |
set_page_dirty(page); |
} |
i++; |
} |
} |
513,7 → 517,7 |
void |
i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) |
{ |
struct scatterlist *sg; |
struct sg_page_iter sg_iter; |
int page_count = obj->base.size >> PAGE_SHIFT; |
int i; |
527,12 → 531,13 |
} |
} |
for_each_sg(obj->pages->sgl, sg, page_count, i) { |
struct page *page = sg_page(sg); |
if (page_to_phys(page) & (1 << 17)) |
i = 0; |
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { |
if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) |
__set_bit(i, obj->bit_17); |
else |
__clear_bit(i, obj->bit_17); |
i++; |
} |
} |
/drivers/video/drm/i915/i915_irq.c |
---|
26,7 → 26,7 |
* |
*/ |
#define pr_fmt(fmt) ": " fmt |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
#include <linux/slab.h> |
#include <drm/drmP.h> |
35,7 → 35,61 |
#include "i915_trace.h" |
#include "intel_drv.h" |
static const u32 hpd_ibx[] = { |
[HPD_CRT] = SDE_CRT_HOTPLUG, |
[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, |
[HPD_PORT_B] = SDE_PORTB_HOTPLUG, |
[HPD_PORT_C] = SDE_PORTC_HOTPLUG, |
[HPD_PORT_D] = SDE_PORTD_HOTPLUG |
}; |
static const u32 hpd_cpt[] = { |
[HPD_CRT] = SDE_CRT_HOTPLUG_CPT, |
[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT, |
[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, |
[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, |
[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT |
}; |
static const u32 hpd_mask_i915[] = { |
[HPD_CRT] = CRT_HOTPLUG_INT_EN, |
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, |
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, |
[HPD_PORT_B] = PORTB_HOTPLUG_INT_EN, |
[HPD_PORT_C] = PORTC_HOTPLUG_INT_EN, |
[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN |
}; |
static const u32 hpd_status_gen4[] = { |
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS, |
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, |
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, |
[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, |
[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, |
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS |
}; |
static const u32 hpd_status_i965[] = { |
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS, |
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965, |
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965, |
[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, |
[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, |
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS |
}; |
static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ |
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS, |
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, |
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, |
[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, |
[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, |
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS |
}; |
static void ibx_hpd_irq_setup(struct drm_device *dev); |
static void i915_hpd_irq_setup(struct drm_device *dev); |
#define pr_err(fmt, ...) \ |
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
58,7 → 112,7 |
} |
} |
static inline void |
static void |
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) |
{ |
if ((dev_priv->irq_mask & mask) != mask) { |
71,27 → 125,31 |
void |
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) |
{ |
if ((dev_priv->pipestat[pipe] & mask) != mask) { |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0x7fff0000; |
dev_priv->pipestat[pipe] |= mask; |
if ((pipestat & mask) == mask) |
return; |
/* Enable the interrupt, clear any pending status */ |
I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); |
pipestat |= mask | (mask >> 16); |
I915_WRITE(reg, pipestat); |
POSTING_READ(reg); |
} |
} |
void |
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) |
{ |
if ((dev_priv->pipestat[pipe] & mask) != 0) { |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0x7fff0000; |
dev_priv->pipestat[pipe] &= ~mask; |
I915_WRITE(reg, dev_priv->pipestat[pipe]); |
if ((pipestat & mask) == 0) |
return; |
pipestat &= ~mask; |
I915_WRITE(reg, pipestat); |
POSTING_READ(reg); |
} |
} |
#if 0 |
/** |
190,9 → 248,109 |
return I915_READ(reg); |
} |
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, |
int *vpos, int *hpos) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 vbl = 0, position = 0; |
int vbl_start, vbl_end, htotal, vtotal; |
bool in_vbl = true; |
int ret = 0; |
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, |
pipe); |
if (!i915_pipe_enabled(dev, pipe)) { |
DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " |
"pipe %c\n", pipe_name(pipe)); |
return 0; |
} |
/* Get vtotal. */ |
vtotal = 1 + ((I915_READ(VTOTAL(cpu_transcoder)) >> 16) & 0x1fff); |
if (INTEL_INFO(dev)->gen >= 4) { |
/* No obvious pixelcount register. Only query vertical |
* scanout position from Display scan line register. |
*/ |
position = I915_READ(PIPEDSL(pipe)); |
/* Decode into vertical scanout position. Don't have |
* horizontal scanout position. |
*/ |
*vpos = position & 0x1fff; |
*hpos = 0; |
} else { |
/* Have access to pixelcount since start of frame. |
* We can split this into vertical and horizontal |
* scanout position. |
*/ |
position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; |
htotal = 1 + ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff); |
*vpos = position / htotal; |
*hpos = position - (*vpos * htotal); |
} |
/* Query vblank area. */ |
vbl = I915_READ(VBLANK(cpu_transcoder)); |
/* Test position against vblank region. */ |
vbl_start = vbl & 0x1fff; |
vbl_end = (vbl >> 16) & 0x1fff; |
if ((*vpos < vbl_start) || (*vpos > vbl_end)) |
in_vbl = false; |
/* Inside "upper part" of vblank area? Apply corrective offset: */ |
if (in_vbl && (*vpos >= vbl_start)) |
*vpos = *vpos - vtotal; |
/* Readouts valid? */ |
if (vbl > 0) |
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; |
/* In vblank? */ |
if (in_vbl) |
ret |= DRM_SCANOUTPOS_INVBL; |
return ret; |
} |
static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, |
int *max_error, |
struct timeval *vblank_time, |
unsigned flags) |
{ |
struct drm_crtc *crtc; |
if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) { |
DRM_ERROR("Invalid crtc %d\n", pipe); |
return -EINVAL; |
} |
/* Get drm_crtc to timestamp: */ |
crtc = intel_get_crtc_for_pipe(dev, pipe); |
if (crtc == NULL) { |
DRM_ERROR("Invalid crtc %d\n", pipe); |
return -EINVAL; |
} |
if (!crtc->enabled) { |
DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); |
return -EBUSY; |
} |
/* Helper routine in DRM core does all the work: */ |
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, |
vblank_time, flags, |
crtc); |
} |
/* |
* Handle hotplug events outside the interrupt handler proper. |
*/ |
#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) |
static void i915_hotplug_work_func(struct work_struct *work) |
{ |
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, |
199,7 → 357,11 |
hotplug_work); |
struct drm_device *dev = dev_priv->dev; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_encoder *encoder; |
struct intel_connector *intel_connector; |
struct intel_encoder *intel_encoder; |
struct drm_connector *connector; |
unsigned long irqflags; |
bool hpd_disabled = false; |
/* HPD irq before everything is fully set up. */ |
if (!dev_priv->enable_hotplug_processing) |
208,10 → 370,37 |
mutex_lock(&mode_config->mutex); |
DRM_DEBUG_KMS("running encoder hotplug functions\n"); |
list_for_each_entry(encoder, &mode_config->encoder_list, base.head) |
if (encoder->hot_plug) |
encoder->hot_plug(encoder); |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
list_for_each_entry(connector, &mode_config->connector_list, head) { |
intel_connector = to_intel_connector(connector); |
intel_encoder = intel_connector->encoder; |
if (intel_encoder->hpd_pin > HPD_NONE && |
dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && |
connector->polled == DRM_CONNECTOR_POLL_HPD) { |
DRM_INFO("HPD interrupt storm detected on connector %s: " |
"switching from hotplug detection to polling\n", |
drm_get_connector_name(connector)); |
dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; |
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
| DRM_CONNECTOR_POLL_DISCONNECT; |
hpd_disabled = true; |
} |
} |
/* if there were no outputs to poll, poll was disabled, |
* therefore make sure it's enabled when disabling HPD on |
* some connectors */ |
if (hpd_disabled) { |
drm_kms_helper_poll_enable(dev); |
// mod_timer(&dev_priv->hotplug_reenable_timer, |
// jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); |
} |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) |
if (intel_encoder->hot_plug) |
intel_encoder->hot_plug(intel_encoder); |
mutex_unlock(&mode_config->mutex); |
/* Just fire off a uevent and let userspace tell us what to do */ |
218,6 → 407,46 |
drm_helper_hpd_irq_event(dev); |
} |
static void ironlake_handle_rps_change(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
u32 busy_up, busy_down, max_avg, min_avg; |
u8 new_delay; |
unsigned long flags; |
spin_lock_irqsave(&mchdev_lock, flags); |
I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); |
new_delay = dev_priv->ips.cur_delay; |
I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); |
busy_up = I915_READ(RCPREVBSYTUPAVG); |
busy_down = I915_READ(RCPREVBSYTDNAVG); |
max_avg = I915_READ(RCBMAXAVG); |
min_avg = I915_READ(RCBMINAVG); |
/* Handle RCS change request from hw */ |
if (busy_up > max_avg) { |
if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay) |
new_delay = dev_priv->ips.cur_delay - 1; |
if (new_delay < dev_priv->ips.max_delay) |
new_delay = dev_priv->ips.max_delay; |
} else if (busy_down < min_avg) { |
if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay) |
new_delay = dev_priv->ips.cur_delay + 1; |
if (new_delay > dev_priv->ips.min_delay) |
new_delay = dev_priv->ips.min_delay; |
} |
if (ironlake_set_drps(dev, new_delay)) |
dev_priv->ips.cur_delay = new_delay; |
spin_unlock_irqrestore(&mchdev_lock, flags); |
return; |
} |
static void notify_ring(struct drm_device *dev, |
struct intel_ring_buffer *ring) |
{ |
359,7 → 588,6 |
struct drm_i915_private *dev_priv, |
u32 gt_iir) |
{ |
// printf("%s\n", __FUNCTION__); |
if (gt_iir & (GEN6_RENDER_USER_INTERRUPT | |
GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT)) |
404,6 → 632,45 |
// queue_work(dev_priv->wq, &dev_priv->rps.work); |
} |
#define HPD_STORM_DETECT_PERIOD 1000 |
#define HPD_STORM_THRESHOLD 5 |
static inline bool hotplug_irq_storm_detect(struct drm_device *dev, |
u32 hotplug_trigger, |
const u32 *hpd) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
unsigned long irqflags; |
int i; |
bool ret = false; |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
for (i = 1; i < HPD_NUM_PINS; i++) { |
if (!(hpd[i] & hotplug_trigger) || |
dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) |
continue; |
// if (!time_in_range(GetTimerTicks(), dev_priv->hpd_stats[i].hpd_last_jiffies, |
// dev_priv->hpd_stats[i].hpd_last_jiffies |
// + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { |
// dev_priv->hpd_stats[i].hpd_last_jiffies = GetTimerTicks; |
// dev_priv->hpd_stats[i].hpd_cnt = 0; |
// } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { |
// dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; |
// DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); |
// ret = true; |
// } else { |
dev_priv->hpd_stats[i].hpd_cnt++; |
// } |
} |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
return ret; |
} |
static void gmbus_irq_handler(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; |
474,13 → 741,16 |
/* Consume port. Then clear IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) { |
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); |
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; |
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", |
hotplug_status); |
if (hotplug_status & dev_priv->hotplug_supported_mask) |
if (hotplug_trigger) { |
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) |
i915_hpd_irq_setup(dev); |
queue_work(dev_priv->wq, |
&dev_priv->hotplug_work); |
} |
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
I915_READ(PORT_HOTPLUG_STAT); |
} |
504,10 → 774,13 |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
int pipe; |
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; |
if (pch_iir & SDE_HOTPLUG_MASK) |
if (hotplug_trigger) { |
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx)) |
ibx_hpd_irq_setup(dev); |
queue_work(dev_priv->wq, &dev_priv->hotplug_work); |
} |
if (pch_iir & SDE_AUDIO_POWER_MASK) |
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", |
(pch_iir & SDE_AUDIO_POWER_MASK) >> |
550,10 → 823,13 |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
int pipe; |
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; |
if (pch_iir & SDE_HOTPLUG_MASK_CPT) |
if (hotplug_trigger) { |
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt)) |
ibx_hpd_irq_setup(dev); |
queue_work(dev_priv->wq, &dev_priv->hotplug_work); |
} |
if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) |
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", |
(pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> |
582,7 → 858,7 |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; |
u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier = 0; |
irqreturn_t ret = IRQ_NONE; |
int i; |
597,9 → 873,11 |
* able to process them after we restore SDEIER (as soon as we restore |
* it, we'll get an interrupt if SDEIIR still has something to process |
* due to its back queue). */ |
if (!HAS_PCH_NOP(dev)) { |
sde_ier = I915_READ(SDEIER); |
I915_WRITE(SDEIER, 0); |
POSTING_READ(SDEIER); |
} |
gt_iir = I915_READ(GTIIR); |
if (gt_iir) { |
626,7 → 904,7 |
} |
#endif |
/* check event from PCH */ |
if (de_iir & DE_PCH_EVENT_IVB) { |
if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) { |
u32 pch_iir = I915_READ(SDEIIR); |
cpt_irq_handler(dev, pch_iir); |
649,8 → 927,10 |
I915_WRITE(DEIER, de_ier); |
POSTING_READ(DEIER); |
if (!HAS_PCH_NOP(dev)) { |
I915_WRITE(SDEIER, sde_ier); |
POSTING_READ(SDEIER); |
} |
return ret; |
} |
792,24 → 1072,23 |
#ifdef CONFIG_DEBUG_FS |
static struct drm_i915_error_object * |
i915_error_object_create(struct drm_i915_private *dev_priv, |
struct drm_i915_gem_object *src) |
i915_error_object_create_sized(struct drm_i915_private *dev_priv, |
struct drm_i915_gem_object *src, |
const int num_pages) |
{ |
struct drm_i915_error_object *dst; |
int i, count; |
int i; |
u32 reloc_offset; |
if (src == NULL || src->pages == NULL) |
return NULL; |
count = src->base.size / PAGE_SIZE; |
dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC); |
dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC); |
if (dst == NULL) |
return NULL; |
reloc_offset = src->gtt_offset; |
for (i = 0; i < count; i++) { |
for (i = 0; i < num_pages; i++) { |
unsigned long flags; |
void *d; |
859,7 → 1138,7 |
reloc_offset += PAGE_SIZE; |
} |
dst->page_count = count; |
dst->page_count = num_pages; |
dst->gtt_offset = src->gtt_offset; |
return dst; |
870,6 → 1149,9 |
kfree(dst); |
return NULL; |
} |
#define i915_error_object_create(dev_priv, src) \ |
i915_error_object_create_sized((dev_priv), (src), \ |
(src)->base.size>>PAGE_SHIFT) |
static void |
i915_error_object_free(struct drm_i915_error_object *obj) |
968,7 → 1250,7 |
switch (INTEL_INFO(dev)->gen) { |
case 7: |
case 6: |
for (i = 0; i < 16; i++) |
for (i = 0; i < dev_priv->num_fence_regs; i++) |
error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); |
break; |
case 5: |
1076,6 → 1358,26 |
error->cpu_ring_tail[ring->id] = ring->tail; |
} |
static void i915_gem_record_active_context(struct intel_ring_buffer *ring, |
struct drm_i915_error_state *error, |
struct drm_i915_error_ring *ering) |
{ |
struct drm_i915_private *dev_priv = ring->dev->dev_private; |
struct drm_i915_gem_object *obj; |
/* Currently render ring is the only HW context user */ |
if (ring->id != RCS || !error->ccid) |
return; |
list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { |
if ((error->ccid & PAGE_MASK) == obj->gtt_offset) { |
ering->ctx = i915_error_object_create_sized(dev_priv, |
obj, 1); |
} |
} |
} |
static void i915_gem_record_rings(struct drm_device *dev, |
struct drm_i915_error_state *error) |
{ |
1093,6 → 1395,9 |
error->ring[i].ringbuffer = |
i915_error_object_create(dev_priv, ring->obj); |
i915_gem_record_active_context(ring, error, &error->ring[i]); |
count = 0; |
list_for_each_entry(request, &ring->request_list, list) |
count++; |
1155,6 → 1460,7 |
kref_init(&error->ref); |
error->eir = I915_READ(EIR); |
error->pgtbl_er = I915_READ(PGTBL_ER); |
if (HAS_HW_CONTEXTS(dev)) |
error->ccid = I915_READ(CCID); |
if (HAS_PCH_SPLIT(dev)) |
1176,6 → 1482,7 |
else if (INTEL_INFO(dev)->gen == 6) |
error->forcewake = I915_READ(FORCEWAKE); |
if (!HAS_PCH_SPLIT(dev)) |
for_each_pipe(pipe) |
error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); |
1390,7 → 1697,7 |
#if 0 |
static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) |
static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
1605,9 → 1912,18 |
I915_WRITE(GTIER, 0x0); |
POSTING_READ(GTIER); |
if (HAS_PCH_NOP(dev)) |
return; |
/* south display irq */ |
I915_WRITE(SDEIMR, 0xffffffff); |
I915_WRITE(SDEIER, 0x0); |
/* |
* SDEIER is also touched by the interrupt handler to work around missed |
* PCH interrupts. Hence we can't update it after the interrupt handler |
* is enabled - instead we unconditionally enable all PCH interrupt |
* sources here, but then only unmask them as needed with SDEIMR. |
*/ |
I915_WRITE(SDEIER, 0xffffffff); |
POSTING_READ(SDEIER); |
} |
1643,6 → 1959,28 |
POSTING_READ(VLV_IER); |
} |
static void ibx_hpd_irq_setup(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_encoder *intel_encoder; |
u32 mask = ~I915_READ(SDEIMR); |
u32 hotplug; |
if (HAS_PCH_IBX(dev)) { |
mask &= ~SDE_HOTPLUG_MASK; |
list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) |
if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) |
mask |= hpd_ibx[intel_encoder->hpd_pin]; |
} else { |
mask &= ~SDE_HOTPLUG_MASK_CPT; |
list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) |
if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) |
mask |= hpd_cpt[intel_encoder->hpd_pin]; |
} |
I915_WRITE(SDEIMR, ~mask); |
/* |
* Enable digital hotplug on the PCH, and configure the DP short pulse |
* duration to 2ms (which is the minimum in the Display Port spec) |
1649,12 → 1987,6 |
* |
* This register is the same on all known PCH chips. |
*/ |
static void ibx_enable_hotplug(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 hotplug; |
hotplug = I915_READ(PCH_PORT_HOTPLUG); |
hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK); |
hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; |
1669,20 → 2001,15 |
u32 mask; |
if (HAS_PCH_IBX(dev)) |
mask = SDE_HOTPLUG_MASK | |
SDE_GMBUS | |
SDE_AUX_MASK; |
mask = SDE_GMBUS | SDE_AUX_MASK; |
else |
mask = SDE_HOTPLUG_MASK_CPT | |
SDE_GMBUS_CPT | |
SDE_AUX_MASK_CPT; |
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; |
if (HAS_PCH_NOP(dev)) |
return; |
I915_WRITE(SDEIIR, I915_READ(SDEIIR)); |
I915_WRITE(SDEIMR, ~mask); |
I915_WRITE(SDEIER, mask); |
POSTING_READ(SDEIER); |
ibx_enable_hotplug(dev); |
} |
static int ironlake_irq_postinstall(struct drm_device *dev) |
1793,9 → 2120,6 |
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | |
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
dev_priv->pipestat[0] = 0; |
dev_priv->pipestat[1] = 0; |
/* Hack for broken MSIs on VLV */ |
// pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000); |
// pci_read_config_word(dev->pdev, 0x98, &msid); |
1839,30 → 2163,6 |
return 0; |
} |
static void valleyview_hpd_irq_setup(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); |
/* Note HDMI and DP share bits */ |
if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTB_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTD_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) |
hotplug_en |= SDVOC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) |
hotplug_en |= SDVOB_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { |
hotplug_en |= CRT_HOTPLUG_INT_EN; |
hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; |
} |
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); |
} |
static void valleyview_irq_uninstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
1902,6 → 2202,9 |
I915_WRITE(GTIER, 0x0); |
I915_WRITE(GTIIR, I915_READ(GTIIR)); |
if (HAS_PCH_NOP(dev)) |
return; |
I915_WRITE(SDEIMR, 0xffffffff); |
I915_WRITE(SDEIER, 0x0); |
I915_WRITE(SDEIIR, I915_READ(SDEIIR)); |
1927,9 → 2230,6 |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
dev_priv->pipestat[0] = 0; |
dev_priv->pipestat[1] = 0; |
I915_WRITE16(EMR, |
~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); |
1952,6 → 2252,37 |
return 0; |
} |
/* |
* Returns true when a page flip has completed. |
*/ |
static bool i8xx_handle_vblank(struct drm_device *dev, |
int pipe, u16 iir) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); |
// if (!drm_handle_vblank(dev, pipe)) |
return false; |
if ((iir & flip_pending) == 0) |
return false; |
// intel_prepare_page_flip(dev, pipe); |
/* We detect FlipDone by looking for the change in PendingFlip from '1' |
* to '0' on the following vblank, i.e. IIR has the Pendingflip |
* asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence |
* the flip is completed (no longer pending). Since this doesn't raise |
* an interrupt per se, we watch for the change at vblank. |
*/ |
if (I915_READ16(ISR) & flip_pending) |
return false; |
intel_finish_page_flip(dev, pipe); |
return true; |
} |
static irqreturn_t i8xx_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
2007,22 → 2338,12 |
notify_ring(dev, &dev_priv->ring[RCS]); |
if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS && |
drm_handle_vblank(dev, 0)) { |
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { |
intel_prepare_page_flip(dev, 0); |
intel_finish_page_flip(dev, 0); |
flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; |
} |
} |
i8xx_handle_vblank(dev, 0, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0); |
if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS && |
drm_handle_vblank(dev, 1)) { |
if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { |
intel_prepare_page_flip(dev, 1); |
intel_finish_page_flip(dev, 1); |
flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; |
} |
} |
i8xx_handle_vblank(dev, 1, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1); |
iir = new_iir; |
} |
2072,9 → 2393,6 |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 enable_mask; |
dev_priv->pipestat[0] = 0; |
dev_priv->pipestat[1] = 0; |
I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); |
/* Unmask the interrupts that we always want on. */ |
2112,34 → 2430,36 |
return 0; |
} |
static void i915_hpd_irq_setup(struct drm_device *dev) |
/* |
* Returns true when a page flip has completed. |
*/ |
static bool i915_handle_vblank(struct drm_device *dev, |
int plane, int pipe, u32 iir) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 hotplug_en; |
drm_i915_private_t *dev_priv = dev->dev_private; |
u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); |
if (I915_HAS_HOTPLUG(dev)) { |
hotplug_en = I915_READ(PORT_HOTPLUG_EN); |
// if (!drm_handle_vblank(dev, pipe)) |
return false; |
if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTB_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTD_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) |
hotplug_en |= SDVOC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) |
hotplug_en |= SDVOB_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { |
hotplug_en |= CRT_HOTPLUG_INT_EN; |
hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; |
} |
if ((iir & flip_pending) == 0) |
return false; |
/* Ignore TV since it's buggy */ |
// intel_prepare_page_flip(dev, plane); |
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); |
/* We detect FlipDone by looking for the change in PendingFlip from '1' |
* to '0' on the following vblank, i.e. IIR has the Pendingflip |
* asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence |
* the flip is completed (no longer pending). Since this doesn't raise |
* an interrupt per se, we watch for the change at vblank. |
*/ |
if (I915_READ(ISR) & flip_pending) |
return false; |
intel_finish_page_flip(dev, pipe); |
return true; |
} |
} |
static irqreturn_t i915_irq_handler(int irq, void *arg) |
{ |
2150,10 → 2470,6 |
u32 flip_mask = |
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; |
u32 flip[2] = { |
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
}; |
int pipe, ret = IRQ_NONE; |
atomic_inc(&dev_priv->irq_received); |
2194,13 → 2510,16 |
if ((I915_HAS_HOTPLUG(dev)) && |
(iir & I915_DISPLAY_PORT_INTERRUPT)) { |
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); |
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; |
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", |
hotplug_status); |
if (hotplug_status & dev_priv->hotplug_supported_mask) |
if (hotplug_trigger) { |
if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) |
i915_hpd_irq_setup(dev); |
queue_work(dev_priv->wq, |
&dev_priv->hotplug_work); |
} |
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
POSTING_READ(PORT_HOTPLUG_STAT); |
} |
2215,15 → 2534,11 |
int plane = pipe; |
if (IS_MOBILE(dev)) |
plane = !plane; |
if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS /* && |
drm_handle_vblank(dev, pipe) */) { |
if (iir & flip[plane]) { |
// intel_prepare_page_flip(dev, plane); |
// intel_finish_page_flip(dev, pipe); |
flip_mask &= ~flip[plane]; |
} |
} |
if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && |
i915_handle_vblank(dev, plane, pipe, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); |
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) |
blc_event = true; |
} |
2311,13 → 2626,13 |
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); |
enable_mask = ~dev_priv->irq_mask; |
enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); |
enable_mask |= I915_USER_INTERRUPT; |
if (IS_G4X(dev)) |
enable_mask |= I915_BSD_USER_INTERRUPT; |
dev_priv->pipestat[0] = 0; |
dev_priv->pipestat[1] = 0; |
i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); |
/* |
2347,33 → 2662,21 |
return 0; |
} |
static void i965_hpd_irq_setup(struct drm_device *dev) |
static void i915_hpd_irq_setup(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_encoder *intel_encoder; |
u32 hotplug_en; |
if (I915_HAS_HOTPLUG(dev)) { |
hotplug_en = I915_READ(PORT_HOTPLUG_EN); |
hotplug_en &= ~HOTPLUG_INT_EN_MASK; |
/* Note HDMI and DP share hotplug bits */ |
hotplug_en = 0; |
if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTB_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) |
hotplug_en |= PORTD_HOTPLUG_INT_EN; |
if (IS_G4X(dev)) { |
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) |
hotplug_en |= SDVOC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X) |
hotplug_en |= SDVOB_HOTPLUG_INT_EN; |
} else { |
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965) |
hotplug_en |= SDVOC_HOTPLUG_INT_EN; |
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965) |
hotplug_en |= SDVOB_HOTPLUG_INT_EN; |
} |
if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { |
hotplug_en |= CRT_HOTPLUG_INT_EN; |
/* enable bits are the same for all generations */ |
list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) |
if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) |
hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; |
/* Programming the CRT detection parameters tends |
to generate a spurious hotplug event about three |
seconds later. So just do it once. |
2380,13 → 2683,13 |
*/ |
if (IS_G4X(dev)) |
hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; |
hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK; |
hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; |
} |
/* Ignore TV since it's buggy */ |
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); |
} |
} |
static irqreturn_t i965_irq_handler(int irq, void *arg) |
{ |
2397,6 → 2700,9 |
unsigned long irqflags; |
int irq_received; |
int ret = IRQ_NONE, pipe; |
u32 flip_mask = |
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; |
atomic_inc(&dev_priv->irq_received); |
2405,7 → 2711,7 |
for (;;) { |
bool blc_event = false; |
irq_received = iir != 0; |
irq_received = (iir & ~flip_mask) != 0; |
/* Can't rely on pipestat interrupt bit in iir as it might |
* have been cleared after the pipestat interrupt was received. |
2441,18 → 2747,24 |
/* Consume port. Then clear IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) { |
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); |
u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? |
HOTPLUG_INT_STATUS_G4X : |
HOTPLUG_INT_STATUS_I965); |
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", |
hotplug_status); |
if (hotplug_status & dev_priv->hotplug_supported_mask) |
if (hotplug_trigger) { |
if (hotplug_irq_storm_detect(dev, hotplug_trigger, |
IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965)) |
i915_hpd_irq_setup(dev); |
queue_work(dev_priv->wq, |
&dev_priv->hotplug_work); |
} |
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
I915_READ(PORT_HOTPLUG_STAT); |
} |
I915_WRITE(IIR, iir); |
I915_WRITE(IIR, iir & ~flip_mask); |
new_iir = I915_READ(IIR); /* Flush posted writes */ |
if (iir & I915_USER_INTERRUPT) |
2460,18 → 2772,10 |
if (iir & I915_BSD_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[VCS]); |
// if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) |
// intel_prepare_page_flip(dev, 0); |
// if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) |
// intel_prepare_page_flip(dev, 1); |
for_each_pipe(pipe) { |
// if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && |
// drm_handle_vblank(dev, pipe)) { |
// i915_pageflip_stall_check(dev, pipe); |
// intel_finish_page_flip(dev, pipe); |
// } |
if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && |
i915_handle_vblank(dev, pipe, pipe, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); |
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) |
blc_event = true; |
2544,16 → 2848,18 |
dev->driver->irq_handler = valleyview_irq_handler; |
dev->driver->irq_preinstall = valleyview_irq_preinstall; |
dev->driver->irq_postinstall = valleyview_irq_postinstall; |
dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup; |
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; |
} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { |
/* Share pre & uninstall handlers with ILK/SNB */ |
dev->driver->irq_handler = ivybridge_irq_handler; |
dev->driver->irq_preinstall = ironlake_irq_preinstall; |
dev->driver->irq_postinstall = ivybridge_irq_postinstall; |
dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; |
} else if (HAS_PCH_SPLIT(dev)) { |
dev->driver->irq_handler = ironlake_irq_handler; |
dev->driver->irq_preinstall = ironlake_irq_preinstall; |
dev->driver->irq_postinstall = ironlake_irq_postinstall; |
dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; |
} else { |
if (INTEL_INFO(dev)->gen == 2) { |
} else if (INTEL_INFO(dev)->gen == 3) { |
2565,7 → 2871,7 |
dev->driver->irq_preinstall = i965_irq_preinstall; |
dev->driver->irq_postinstall = i965_irq_postinstall; |
dev->driver->irq_handler = i965_irq_handler; |
dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup; |
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; |
} |
} |
} |
2573,7 → 2879,20 |
void intel_hpd_init(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct drm_connector *connector; |
int i; |
for (i = 1; i < HPD_NUM_PINS; i++) { |
dev_priv->hpd_stats[i].hpd_cnt = 0; |
dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; |
} |
list_for_each_entry(connector, &mode_config->connector_list, head) { |
struct intel_connector *intel_connector = to_intel_connector(connector); |
connector->polled = intel_connector->polled; |
if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
} |
if (dev_priv->display.hpd_irq_setup) |
dev_priv->display.hpd_irq_setup(dev); |
} |
/drivers/video/drm/i915/i915_reg.h |
---|
46,8 → 46,6 |
#define SNB_GMCH_GGMS_MASK 0x3 |
#define SNB_GMCH_GMS_SHIFT 3 /* Graphics Mode Select */ |
#define SNB_GMCH_GMS_MASK 0x1f |
#define IVB_GMCH_GMS_SHIFT 4 |
#define IVB_GMCH_GMS_MASK 0xf |
/* PCI config space */ |
91,6 → 89,7 |
#define GRDOM_FULL (0<<2) |
#define GRDOM_RENDER (1<<2) |
#define GRDOM_MEDIA (3<<2) |
#define GRDOM_MASK (3<<2) |
#define GRDOM_RESET_ENABLE (1<<0) |
#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ |
121,10 → 120,17 |
#define GAM_ECOCHK 0x4090 |
#define ECOCHK_SNB_BIT (1<<10) |
#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) |
#define ECOCHK_PPGTT_CACHE64B (0x3<<3) |
#define ECOCHK_PPGTT_CACHE4B (0x0<<3) |
#define ECOCHK_PPGTT_GFDT_IVB (0x1<<4) |
#define ECOCHK_PPGTT_LLC_IVB (0x1<<3) |
#define ECOCHK_PPGTT_UC_HSW (0x1<<3) |
#define ECOCHK_PPGTT_WT_HSW (0x2<<3) |
#define ECOCHK_PPGTT_WB_HSW (0x3<<3) |
#define GAC_ECO_BITS 0x14090 |
#define ECOBITS_SNB_BIT (1<<13) |
#define ECOBITS_PPGTT_CACHE64B (3<<8) |
#define ECOBITS_PPGTT_CACHE4B (0<<8) |
422,6 → 428,7 |
#define FENCE_REG_SANDYBRIDGE_0 0x100000 |
#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32 |
#define GEN7_FENCE_MAX_PITCH_VAL 0x0800 |
/* control register for cpu gtt access */ |
#define TILECTL 0x101000 |
522,6 → 529,9 |
#define GEN7_ERR_INT 0x44040 |
#define ERR_INT_MMIO_UNCLAIMED (1<<13) |
#define FPGA_DBG 0x42300 |
#define FPGA_DBG_RM_NOCLAIM (1<<31) |
#define DERRMR 0x44050 |
/* GM45+ chicken bits -- debug workaround bits that may be required |
591,6 → 601,7 |
#define I915_USER_INTERRUPT (1<<1) |
#define I915_ASLE_INTERRUPT (1<<0) |
#define I915_BSD_USER_INTERRUPT (1<<25) |
#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ |
#define EIR 0x020b0 |
#define EMR 0x020b4 |
#define ESR 0x020b8 |
1197,6 → 1208,9 |
#define MCHBAR_MIRROR_BASE_SNB 0x140000 |
/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ |
#define DCLK 0x5e04 |
/** 915-945 and GM965 MCH register controlling DRAM channel access */ |
#define DCC 0x10200 |
#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) |
1637,6 → 1651,12 |
#define SDVOC_HOTPLUG_INT_EN (1 << 25) |
#define TV_HOTPLUG_INT_EN (1 << 18) |
#define CRT_HOTPLUG_INT_EN (1 << 9) |
#define HOTPLUG_INT_EN_MASK (PORTB_HOTPLUG_INT_EN | \ |
PORTC_HOTPLUG_INT_EN | \ |
PORTD_HOTPLUG_INT_EN | \ |
SDVOC_HOTPLUG_INT_EN | \ |
SDVOB_HOTPLUG_INT_EN | \ |
CRT_HOTPLUG_INT_EN) |
#define CRT_HOTPLUG_FORCE_DETECT (1 << 3) |
#define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8) |
/* must use period 64 on GM45 according to docs */ |
1675,19 → 1695,48 |
#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) |
#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) |
#define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6) |
#define HOTPLUG_INT_STATUS_G4X (CRT_HOTPLUG_INT_STATUS | \ |
SDVOB_HOTPLUG_INT_STATUS_G4X | \ |
SDVOC_HOTPLUG_INT_STATUS_G4X | \ |
PORTB_HOTPLUG_INT_STATUS | \ |
PORTC_HOTPLUG_INT_STATUS | \ |
PORTD_HOTPLUG_INT_STATUS) |
/* SDVO port control */ |
#define SDVOB 0x61140 |
#define SDVOC 0x61160 |
#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \ |
SDVOB_HOTPLUG_INT_STATUS_I965 | \ |
SDVOC_HOTPLUG_INT_STATUS_I965 | \ |
PORTB_HOTPLUG_INT_STATUS | \ |
PORTC_HOTPLUG_INT_STATUS | \ |
PORTD_HOTPLUG_INT_STATUS) |
#define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \ |
SDVOB_HOTPLUG_INT_STATUS_I915 | \ |
SDVOC_HOTPLUG_INT_STATUS_I915 | \ |
PORTB_HOTPLUG_INT_STATUS | \ |
PORTC_HOTPLUG_INT_STATUS | \ |
PORTD_HOTPLUG_INT_STATUS) |
/* SDVO and HDMI port control. |
* The same register may be used for SDVO or HDMI */ |
#define GEN3_SDVOB 0x61140 |
#define GEN3_SDVOC 0x61160 |
#define GEN4_HDMIB GEN3_SDVOB |
#define GEN4_HDMIC GEN3_SDVOC |
#define PCH_SDVOB 0xe1140 |
#define PCH_HDMIB PCH_SDVOB |
#define PCH_HDMIC 0xe1150 |
#define PCH_HDMID 0xe1160 |
/* Gen 3 SDVO bits: */ |
#define SDVO_ENABLE (1 << 31) |
#define SDVO_PIPE_SEL(pipe) ((pipe) << 30) |
#define SDVO_PIPE_SEL_MASK (1 << 30) |
#define SDVO_PIPE_B_SELECT (1 << 30) |
#define SDVO_STALL_SELECT (1 << 29) |
#define SDVO_INTERRUPT_ENABLE (1 << 26) |
/** |
* 915G/GM SDVO pixel multiplier. |
* |
* Programmed value is multiplier - 1, up to 5x. |
* |
* \sa DPLL_MD_UDI_MULTIPLIER_MASK |
*/ |
#define SDVO_PORT_MULTIPLY_MASK (7 << 23) |
1695,24 → 1744,36 |
#define SDVO_PHASE_SELECT_MASK (15 << 19) |
#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) |
#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) |
#define SDVOC_GANG_MODE (1 << 16) |
#define SDVO_ENCODING_SDVO (0x0 << 10) |
#define SDVO_ENCODING_HDMI (0x2 << 10) |
/** Requird for HDMI operation */ |
#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) |
#define SDVO_COLOR_RANGE_16_235 (1 << 8) |
#define SDVO_BORDER_ENABLE (1 << 7) |
#define SDVOC_GANG_MODE (1 << 16) /* Port C only */ |
#define SDVO_BORDER_ENABLE (1 << 7) /* SDVO only */ |
#define SDVOB_PCIE_CONCURRENCY (1 << 3) /* Port B only */ |
#define SDVO_DETECTED (1 << 2) |
/* Bits to be preserved when writing */ |
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \ |
SDVO_INTERRUPT_ENABLE) |
#define SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE) |
/* Gen 4 SDVO/HDMI bits: */ |
#define SDVO_COLOR_FORMAT_8bpc (0 << 26) |
#define SDVO_ENCODING_SDVO (0 << 10) |
#define SDVO_ENCODING_HDMI (2 << 10) |
#define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ |
#define HDMI_MODE_SELECT_DVI (0 << 9) /* HDMI only */ |
#define HDMI_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ |
#define SDVO_AUDIO_ENABLE (1 << 6) |
/** New with 965, default is to be set */ |
/* VSYNC/HSYNC bits new with 965, default is to be set */ |
#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) |
/** New with 965, default is to be set */ |
#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) |
#define SDVOB_PCIE_CONCURRENCY (1 << 3) |
#define SDVO_DETECTED (1 << 2) |
/* Bits to be preserved when writing */ |
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) |
#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) |
/* Gen 5 (IBX) SDVO/HDMI bits: */ |
#define HDMI_COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */ |
#define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ |
/* Gen 6 (CPT) SDVO/HDMI bits: */ |
#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29) |
#define SDVO_PIPE_SEL_MASK_CPT (3 << 29) |
/* DVO port control */ |
#define DVOA 0x61120 |
#define DVOB 0x61140 |
1898,7 → 1959,7 |
#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) |
/* Backlight control */ |
#define BLC_PWM_CTL2 0x61250 /* 965+ only */ |
#define BLC_PWM_CTL2 (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */ |
#define BLM_PWM_ENABLE (1 << 31) |
#define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */ |
#define BLM_PIPE_SELECT (1 << 29) |
1917,7 → 1978,7 |
#define BLM_PHASE_IN_COUNT_MASK (0xff << 8) |
#define BLM_PHASE_IN_INCR_SHIFT (0) |
#define BLM_PHASE_IN_INCR_MASK (0xff << 0) |
#define BLC_PWM_CTL 0x61254 |
#define BLC_PWM_CTL (dev_priv->info->display_mmio_offset + 0x61254) |
/* |
* This is the most significant 15 bits of the number of backlight cycles in a |
* complete cycle of the modulated backlight control. |
1939,7 → 2000,7 |
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe) |
#define BLM_POLARITY_PNV (1 << 0) /* pnv only */ |
#define BLC_HIST_CTL 0x61260 |
#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260) |
/* New registers for PCH-split platforms. Safe where new bits show up, the |
* register layout machtes with gen4 BLC_PWM_CTL[12]. */ |
2589,14 → 2650,14 |
#define _PIPEB_GMCH_DATA_M 0x71050 |
/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ |
#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) |
#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 |
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ |
#define TU_SIZE_MASK (0x3f << 25) |
#define PIPE_GMCH_DATA_M_MASK (0xffffff) |
#define DATA_LINK_M_N_MASK (0xffffff) |
#define DATA_LINK_N_MAX (0x800000) |
#define _PIPEA_GMCH_DATA_N 0x70054 |
#define _PIPEB_GMCH_DATA_N 0x71054 |
#define PIPE_GMCH_DATA_N_MASK (0xffffff) |
/* |
* Computing Link M and N values for the Display Port link |
2611,11 → 2672,9 |
#define _PIPEA_DP_LINK_M 0x70060 |
#define _PIPEB_DP_LINK_M 0x71060 |
#define PIPEA_DP_LINK_M_MASK (0xffffff) |
#define _PIPEA_DP_LINK_N 0x70064 |
#define _PIPEB_DP_LINK_N 0x71064 |
#define PIPEA_DP_LINK_N_MASK (0xffffff) |
#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) |
#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) |
2776,6 → 2835,8 |
#define DSPFW_HPLL_CURSOR_SHIFT 16 |
#define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) |
#define DSPFW_HPLL_SR_MASK (0x1ff) |
#define DSPFW4 (dev_priv->info->display_mmio_offset + 0x70070) |
#define DSPFW7 (dev_priv->info->display_mmio_offset + 0x7007c) |
/* drain latency register values*/ |
#define DRAIN_LATENCY_PRECISION_32 32 |
3233,6 → 3294,63 |
#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) |
#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) |
#define _SPACNTR 0x72180 |
#define SP_ENABLE (1<<31) |
#define SP_GEAMMA_ENABLE (1<<30) |
#define SP_PIXFORMAT_MASK (0xf<<26) |
#define SP_FORMAT_YUV422 (0<<26) |
#define SP_FORMAT_BGR565 (5<<26) |
#define SP_FORMAT_BGRX8888 (6<<26) |
#define SP_FORMAT_BGRA8888 (7<<26) |
#define SP_FORMAT_RGBX1010102 (8<<26) |
#define SP_FORMAT_RGBA1010102 (9<<26) |
#define SP_FORMAT_RGBX8888 (0xe<<26) |
#define SP_FORMAT_RGBA8888 (0xf<<26) |
#define SP_SOURCE_KEY (1<<22) |
#define SP_YUV_BYTE_ORDER_MASK (3<<16) |
#define SP_YUV_ORDER_YUYV (0<<16) |
#define SP_YUV_ORDER_UYVY (1<<16) |
#define SP_YUV_ORDER_YVYU (2<<16) |
#define SP_YUV_ORDER_VYUY (3<<16) |
#define SP_TILED (1<<10) |
#define _SPALINOFF 0x72184 |
#define _SPASTRIDE 0x72188 |
#define _SPAPOS 0x7218c |
#define _SPASIZE 0x72190 |
#define _SPAKEYMINVAL 0x72194 |
#define _SPAKEYMSK 0x72198 |
#define _SPASURF 0x7219c |
#define _SPAKEYMAXVAL 0x721a0 |
#define _SPATILEOFF 0x721a4 |
#define _SPACONSTALPHA 0x721a8 |
#define _SPAGAMC 0x721f4 |
#define _SPBCNTR 0x72280 |
#define _SPBLINOFF 0x72284 |
#define _SPBSTRIDE 0x72288 |
#define _SPBPOS 0x7228c |
#define _SPBSIZE 0x72290 |
#define _SPBKEYMINVAL 0x72294 |
#define _SPBKEYMSK 0x72298 |
#define _SPBSURF 0x7229c |
#define _SPBKEYMAXVAL 0x722a0 |
#define _SPBTILEOFF 0x722a4 |
#define _SPBCONSTALPHA 0x722a8 |
#define _SPBGAMC 0x722f4 |
#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) |
#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) |
#define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE) |
#define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS) |
#define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE) |
#define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL) |
#define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK) |
#define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF) |
#define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL) |
#define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF) |
#define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA) |
#define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC) |
/* VBIOS regs */ |
#define VGACNTRL 0x71400 |
# define VGA_DISP_DISABLE (1 << 31) |
3282,8 → 3400,6 |
#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) |
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ |
#define TU_SIZE_MASK 0x7e000000 |
#define PIPE_DATA_M1_OFFSET 0 |
#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) |
#define PIPE_DATA_N1_OFFSET 0 |
3456,6 → 3572,9 |
#define DISP_ARB_CTL 0x45000 |
#define DISP_TILE_SURFACE_SWIZZLING (1<<13) |
#define DISP_FBC_WM_DIS (1<<15) |
#define GEN7_MSG_CTL 0x45010 |
#define WAIT_FOR_PCH_RESET_ACK (1<<1) |
#define WAIT_FOR_PCH_FLR_ACK (1<<0) |
/* GEN7 chicken */ |
#define GEN7_COMMON_SLICE_CHICKEN1 0x7010 |
3508,7 → 3627,11 |
#define SDE_PORTC_HOTPLUG (1 << 9) |
#define SDE_PORTB_HOTPLUG (1 << 8) |
#define SDE_SDVOB_HOTPLUG (1 << 6) |
#define SDE_HOTPLUG_MASK (0xf << 8) |
#define SDE_HOTPLUG_MASK (SDE_CRT_HOTPLUG | \ |
SDE_SDVOB_HOTPLUG | \ |
SDE_PORTB_HOTPLUG | \ |
SDE_PORTC_HOTPLUG | \ |
SDE_PORTD_HOTPLUG) |
#define SDE_TRANSB_CRC_DONE (1 << 5) |
#define SDE_TRANSB_CRC_ERR (1 << 4) |
#define SDE_TRANSB_FIFO_UNDER (1 << 3) |
3531,7 → 3654,9 |
#define SDE_PORTC_HOTPLUG_CPT (1 << 22) |
#define SDE_PORTB_HOTPLUG_CPT (1 << 21) |
#define SDE_CRT_HOTPLUG_CPT (1 << 19) |
#define SDE_SDVOB_HOTPLUG_CPT (1 << 18) |
#define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \ |
SDE_SDVOB_HOTPLUG_CPT | \ |
SDE_PORTD_HOTPLUG_CPT | \ |
SDE_PORTC_HOTPLUG_CPT | \ |
SDE_PORTB_HOTPLUG_CPT) |
3754,14 → 3879,16 |
#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344 |
#define HSW_VIDEO_DIP_GCP_B 0x61210 |
#define HSW_TVIDEO_DIP_CTL(pipe) \ |
_PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) |
#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \ |
_PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) |
#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \ |
_PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) |
#define HSW_TVIDEO_DIP_GCP(pipe) \ |
_PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) |
#define HSW_TVIDEO_DIP_CTL(trans) \ |
_TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) |
#define HSW_TVIDEO_DIP_AVI_DATA(trans) \ |
_TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) |
#define HSW_TVIDEO_DIP_SPD_DATA(trans) \ |
_TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) |
#define HSW_TVIDEO_DIP_GCP(trans) \ |
_TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) |
#define HSW_TVIDEO_DIP_VSC_DATA(trans) \ |
_TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) |
#define _TRANS_HTOTAL_B 0xe1000 |
#define _TRANS_HBLANK_B 0xe1004 |
3827,8 → 3954,11 |
#define _TRANSB_CHICKEN2 0xf1064 |
#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) |
#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) |
#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) |
#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27) |
#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26) |
#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25) |
#define SOUTH_CHICKEN1 0xc2000 |
#define FDIA_PHASE_SYNC_SHIFT_OVR 19 |
#define FDIA_PHASE_SYNC_SHIFT_EN 18 |
3976,34 → 4106,6 |
#define FDI_PLL_CTL_1 0xfe000 |
#define FDI_PLL_CTL_2 0xfe004 |
/* or SDVOB */ |
#define HDMIB 0xe1140 |
#define PORT_ENABLE (1 << 31) |
#define TRANSCODER(pipe) ((pipe) << 30) |
#define TRANSCODER_CPT(pipe) ((pipe) << 29) |
#define TRANSCODER_MASK (1 << 30) |
#define TRANSCODER_MASK_CPT (3 << 29) |
#define COLOR_FORMAT_8bpc (0) |
#define COLOR_FORMAT_12bpc (3 << 26) |
#define SDVOB_HOTPLUG_ENABLE (1 << 23) |
#define SDVO_ENCODING (0) |
#define TMDS_ENCODING (2 << 10) |
#define NULL_PACKET_VSYNC_ENABLE (1 << 9) |
/* CPT */ |
#define HDMI_MODE_SELECT (1 << 9) |
#define DVI_MODE_SELECT (0) |
#define SDVOB_BORDER_ENABLE (1 << 7) |
#define AUDIO_ENABLE (1 << 6) |
#define VSYNC_ACTIVE_HIGH (1 << 4) |
#define HSYNC_ACTIVE_HIGH (1 << 3) |
#define PORT_DETECTED (1 << 2) |
/* PCH SDVOB multiplex with HDMIB */ |
#define PCH_SDVOB HDMIB |
#define HDMIC 0xe1150 |
#define HDMID 0xe1160 |
#define PCH_LVDS 0xe1180 |
#define LVDS_DETECTED (1 << 1) |
4020,6 → 4122,15 |
#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) |
#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) |
#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS) |
#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL) |
#define VLV_PIPE_PP_ON_DELAYS(pipe) \ |
_PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS) |
#define VLV_PIPE_PP_OFF_DELAYS(pipe) \ |
_PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS) |
#define VLV_PIPE_PP_DIVISOR(pipe) \ |
_PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR) |
#define PCH_PP_STATUS 0xc7200 |
#define PCH_PP_CONTROL 0xc7204 |
#define PANEL_UNLOCK_REGS (0xabcd << 16) |
4149,8 → 4260,12 |
#define FORCEWAKE 0xA18C |
#define FORCEWAKE_VLV 0x1300b0 |
#define FORCEWAKE_ACK_VLV 0x1300b4 |
#define FORCEWAKE_MEDIA_VLV 0x1300b8 |
#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc |
#define FORCEWAKE_ACK_HSW 0x130044 |
#define FORCEWAKE_ACK 0x130090 |
#define VLV_GTLC_WAKE_CTRL 0x130090 |
#define VLV_GTLC_PW_STATUS 0x130094 |
#define FORCEWAKE_MT 0xa188 /* multi-threaded */ |
#define FORCEWAKE_KERNEL 0x1 |
#define FORCEWAKE_USER 0x2 |
4184,6 → 4299,7 |
#define GEN6_RPNSWREQ 0xA008 |
#define GEN6_TURBO_DISABLE (1<<31) |
#define GEN6_FREQUENCY(x) ((x)<<25) |
#define HSW_FREQUENCY(x) ((x)<<24) |
#define GEN6_OFFSET(x) ((x)<<19) |
#define GEN6_AGGRESSIVE_TURBO (0<<15) |
#define GEN6_RC_VIDEO_FREQ 0xA00C |
4274,7 → 4390,22 |
#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) |
#define GEN6_PCODE_DATA 0x138128 |
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 |
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 |
#define VLV_IOSF_DOORBELL_REQ 0x182100 |
#define IOSF_DEVFN_SHIFT 24 |
#define IOSF_OPCODE_SHIFT 16 |
#define IOSF_PORT_SHIFT 8 |
#define IOSF_BYTE_ENABLES_SHIFT 4 |
#define IOSF_BAR_SHIFT 1 |
#define IOSF_SB_BUSY (1<<0) |
#define IOSF_PORT_PUNIT 0x4 |
#define VLV_IOSF_DATA 0x182104 |
#define VLV_IOSF_ADDR 0x182108 |
#define PUNIT_OPCODE_REG_READ 6 |
#define PUNIT_OPCODE_REG_WRITE 7 |
#define GEN6_GT_CORE_STATUS 0x138060 |
#define GEN6_CORE_CPD_STATE_MASK (7<<4) |
#define GEN6_RCn_MASK 7 |
/drivers/video/drm/i915/intel_bios.c |
---|
350,12 → 350,14 |
dev_priv->lvds_ssc_freq = |
intel_bios_ssc_frequency(dev, general->ssc_freq); |
dev_priv->display_clock_mode = general->display_clock_mode; |
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n", |
dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", |
dev_priv->int_tv_support, |
dev_priv->int_crt_support, |
dev_priv->lvds_use_ssc, |
dev_priv->lvds_ssc_freq, |
dev_priv->display_clock_mode); |
dev_priv->display_clock_mode, |
dev_priv->fdi_rx_polarity_inverted); |
} |
} |
672,6 → 674,9 |
struct bdb_header *bdb = NULL; |
u8 __iomem *bios = NULL; |
if (HAS_PCH_NOP(dev)) |
return -ENODEV; |
init_vbt_defaults(dev_priv); |
/* XXX Should this validation be moved to intel_opregion.c? */ |
/drivers/video/drm/i915/intel_bios.h |
---|
127,7 → 127,9 |
/* bits 3 */ |
u8 disable_smooth_vision:1; |
u8 single_dvi:1; |
u8 rsvd9:6; /* finish byte */ |
u8 rsvd9:1; |
u8 fdi_rx_polarity_inverted:1; |
u8 rsvd10:4; /* finish byte */ |
/* bits 4 */ |
u8 legacy_monitor_detect; |
/drivers/video/drm/i915/intel_crt.c |
---|
198,10 → 198,14 |
return MODE_OK; |
} |
static bool intel_crt_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static bool intel_crt_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = encoder->base.dev; |
if (HAS_PCH_SPLIT(dev)) |
pipe_config->has_pch_encoder = true; |
return true; |
} |
675,7 → 679,6 |
*/ |
static const struct drm_encoder_helper_funcs crt_encoder_funcs = { |
.mode_fixup = intel_crt_mode_fixup, |
.mode_set = intel_crt_mode_set, |
}; |
745,8 → 748,11 |
else |
crt->adpa_reg = ADPA; |
crt->base.compute_config = intel_crt_compute_config; |
crt->base.disable = intel_disable_crt; |
crt->base.enable = intel_enable_crt; |
if (I915_HAS_HOTPLUG(dev)) |
crt->base.hpd_pin = HPD_CRT; |
if (HAS_DDI(dev)) |
crt->base.get_hw_state = intel_ddi_get_hw_state; |
else |
758,10 → 764,8 |
drm_sysfs_connector_add(connector); |
if (I915_HAS_HOTPLUG(dev)) |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
else |
connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
if (!I915_HAS_HOTPLUG(dev)) |
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
/* |
* Configure the automatic hotplug detection stuff |
768,8 → 772,6 |
*/ |
crt->force_hotplug_required = 0; |
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; |
/* |
* TODO: find a proper way to discover whether we need to set the the |
* polarity and link reversal bits or not, instead of relying on the |
/drivers/video/drm/i915/intel_ddi.c |
---|
898,6 → 898,9 |
plls->spll_refcount++; |
reg = SPLL_CTL; |
intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; |
} else { |
DRM_ERROR("SPLL already in use\n"); |
return false; |
} |
WARN(I915_READ(reg) & SPLL_PLL_ENABLE, |
921,7 → 924,7 |
struct drm_i915_private *dev_priv = crtc->dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
int type = intel_encoder->type; |
uint32_t temp; |
928,7 → 931,7 |
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { |
temp = TRANS_MSA_SYNC_CLK; |
switch (intel_crtc->bpp) { |
switch (intel_crtc->config.pipe_bpp) { |
case 18: |
temp |= TRANS_MSA_6_BPC; |
break; |
942,15 → 945,13 |
temp |= TRANS_MSA_12_BPC; |
break; |
default: |
temp |= TRANS_MSA_8_BPC; |
WARN(1, "%d bpp unsupported by DDI function\n", |
intel_crtc->bpp); |
BUG(); |
} |
I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); |
} |
} |
void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) |
void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) |
{ |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); |
957,7 → 958,7 |
struct drm_encoder *encoder = &intel_encoder->base; |
struct drm_i915_private *dev_priv = crtc->dev->dev_private; |
enum pipe pipe = intel_crtc->pipe; |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
enum port port = intel_ddi_get_encoder_port(intel_encoder); |
int type = intel_encoder->type; |
uint32_t temp; |
966,7 → 967,7 |
temp = TRANS_DDI_FUNC_ENABLE; |
temp |= TRANS_DDI_SELECT_PORT(port); |
switch (intel_crtc->bpp) { |
switch (intel_crtc->config.pipe_bpp) { |
case 18: |
temp |= TRANS_DDI_BPC_6; |
break; |
980,8 → 981,7 |
temp |= TRANS_DDI_BPC_12; |
break; |
default: |
WARN(1, "%d bpp unsupported by transcoder DDI function\n", |
intel_crtc->bpp); |
BUG(); |
} |
if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) |
1150,7 → 1150,7 |
DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); |
return true; |
return false; |
} |
static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, |
1157,7 → 1157,7 |
enum pipe pipe) |
{ |
uint32_t temp, ret; |
enum port port; |
enum port port = I915_MAX_PORTS; |
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, |
pipe); |
int i; |
1173,11 → 1173,17 |
port = i; |
} |
if (port == I915_MAX_PORTS) { |
WARN(1, "Pipe %c enabled on an unknown port\n", |
pipe_name(pipe)); |
ret = PORT_CLK_SEL_NONE; |
} else { |
ret = I915_READ(PORT_CLK_SEL(port)); |
DRM_DEBUG_KMS("Pipe %c connected to port %c using clock " |
"0x%08x\n", pipe_name(pipe), port_name(port), |
ret); |
} |
DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n", |
pipe_name(pipe), port_name(port), ret); |
return ret; |
} |
1217,7 → 1223,7 |
struct drm_i915_private *dev_priv = crtc->dev->dev_private; |
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); |
enum port port = intel_ddi_get_encoder_port(intel_encoder); |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
if (cpu_transcoder != TRANSCODER_EDP) |
I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), |
1227,7 → 1233,7 |
void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) |
{ |
struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
if (cpu_transcoder != TRANSCODER_EDP) |
I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), |
1259,6 → 1265,8 |
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); |
intel_dp_start_link_train(intel_dp); |
intel_dp_complete_link_train(intel_dp); |
if (port != PORT_A) |
intel_dp_stop_link_train(intel_dp); |
} |
} |
1320,6 → 1328,9 |
} else if (type == INTEL_OUTPUT_EDP) { |
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
if (port == PORT_A) |
intel_dp_stop_link_train(intel_dp); |
ironlake_edp_backlight_on(intel_dp); |
} |
1341,15 → 1352,15 |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t tmp; |
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); |
tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); |
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); |
if (type == INTEL_OUTPUT_EDP) { |
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
ironlake_edp_backlight_off(intel_dp); |
} |
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); |
tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); |
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); |
} |
int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) |
1467,19 → 1478,17 |
intel_dp_encoder_destroy(encoder); |
} |
static bool intel_ddi_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static bool intel_ddi_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct intel_encoder *intel_encoder = to_intel_encoder(encoder); |
int type = intel_encoder->type; |
int type = encoder->type; |
WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n"); |
WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); |
if (type == INTEL_OUTPUT_HDMI) |
return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode); |
return intel_hdmi_compute_config(encoder, pipe_config); |
else |
return intel_dp_mode_fixup(encoder, mode, adjusted_mode); |
return intel_dp_compute_config(encoder, pipe_config); |
} |
static const struct drm_encoder_funcs intel_ddi_funcs = { |
1487,7 → 1496,6 |
}; |
static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { |
.mode_fixup = intel_ddi_mode_fixup, |
.mode_set = intel_ddi_mode_set, |
}; |
1527,6 → 1535,7 |
DRM_MODE_ENCODER_TMDS); |
drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); |
intel_encoder->compute_config = intel_ddi_compute_config; |
intel_encoder->enable = intel_enable_ddi; |
intel_encoder->pre_enable = intel_ddi_pre_enable; |
intel_encoder->disable = intel_disable_ddi; |
1537,9 → 1546,7 |
intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & |
DDI_BUF_PORT_REVERSAL; |
if (hdmi_connector) |
intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); |
else |
intel_dig_port->hdmi.sdvox_reg = 0; |
intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); |
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); |
intel_encoder->type = INTEL_OUTPUT_UNKNOWN; |
/drivers/video/drm/i915/intel_display.c |
---|
24,13 → 24,13 |
* Eric Anholt <eric@anholt.net> |
*/ |
//#include <linux/cpufreq.h> |
//#include <linux/dmi.h> |
#include <linux/module.h> |
//#include <linux/input.h> |
#include <linux/i2c.h> |
#include <linux/kernel.h> |
#include <linux/slab.h> |
//#include <linux/vgaarb.h> |
#include <linux/math64.h> |
#include <drm/drm_edid.h> |
#include <drm/drmP.h> |
#include "intel_drv.h" |
43,11 → 43,6 |
phys_addr_t get_bus_addr(void); |
static inline __attribute__((const)) |
bool is_power_of_2(unsigned long n) |
{ |
return (n != 0 && ((n & (n - 1)) == 0)); |
} |
#define MAX_ERRNO 4095 |
83,8 → 78,24 |
struct intel_limit { |
intel_range_t dot, vco, n, m, m1, m2, p, p1; |
intel_p2_t p2; |
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *, |
int, int, intel_clock_t *, intel_clock_t *); |
/** |
* find_pll() - Find the best values for the PLL |
* @limit: limits for the PLL |
* @crtc: current CRTC |
* @target: target frequency in kHz |
* @refclk: reference clock frequency in kHz |
* @match_clock: if provided, @best_clock P divider must |
* match the P divider from @match_clock |
* used for LVDS downclocking |
* @best_clock: best PLL values found |
* |
* Returns true on success, false on failure. |
*/ |
bool (*find_pll)(const intel_limit_t *limit, |
struct drm_crtc *crtc, |
int target, int refclk, |
intel_clock_t *match_clock, |
intel_clock_t *best_clock); |
}; |
/* FDI */ |
483,7 → 494,6 |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
if (intel_is_dual_link_lvds(dev)) { |
/* LVDS dual channel */ |
if (refclk == 100000) |
limit = &intel_limits_ironlake_dual_lvds_100m; |
else |
510,10 → 520,8 |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
if (intel_is_dual_link_lvds(dev)) |
/* LVDS with dual channel */ |
limit = &intel_limits_g4x_dual_channel_lvds; |
else |
/* LVDS with dual channel */ |
limit = &intel_limits_g4x_single_channel_lvds; |
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || |
intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { |
891,7 → 899,7 |
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
return intel_crtc->cpu_transcoder; |
return intel_crtc->config.cpu_transcoder; |
} |
static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) |
1226,8 → 1234,8 |
if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) |
state = true; |
if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP && |
!(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) { |
if (!intel_using_power_well(dev_priv->dev) && |
cpu_transcoder != TRANSCODER_EDP) { |
cur_state = false; |
} else { |
reg = PIPECONF(cpu_transcoder); |
1266,7 → 1274,7 |
int cur_pipe; |
/* Planes are fixed to pipes on ILK+ */ |
if (HAS_PCH_SPLIT(dev_priv->dev)) { |
if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) { |
reg = DSPCNTR(pipe); |
val = I915_READ(reg); |
WARN((val & DISPLAY_PLANE_ENABLE), |
1287,6 → 1295,25 |
} |
} |
static void assert_sprites_disabled(struct drm_i915_private *dev_priv, |
enum pipe pipe) |
{ |
int reg, i; |
u32 val; |
if (!IS_VALLEYVIEW(dev_priv->dev)) |
return; |
/* Need to check both planes against the pipe */ |
for (i = 0; i < dev_priv->num_plane; i++) { |
reg = SPCNTR(pipe, i); |
val = I915_READ(reg); |
WARN((val & SP_ENABLE), |
"sprite %d assertion failure, should be off on pipe %c but is still active\n", |
pipe * 2 + i, pipe_name(pipe)); |
} |
} |
static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) |
{ |
u32 val; |
1339,14 → 1366,14 |
static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, |
enum pipe pipe, u32 val) |
{ |
if ((val & PORT_ENABLE) == 0) |
if ((val & SDVO_ENABLE) == 0) |
return false; |
if (HAS_PCH_CPT(dev_priv->dev)) { |
if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) |
if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe)) |
return false; |
} else { |
if ((val & TRANSCODER_MASK) != TRANSCODER(pipe)) |
if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe)) |
return false; |
} |
return true; |
1404,7 → 1431,7 |
"PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", |
reg, pipe_name(pipe)); |
WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0 |
WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 |
&& (val & SDVO_PIPE_B_SELECT), |
"IBX PCH hdmi port still using transcoder B\n"); |
} |
1431,9 → 1458,9 |
"PCH LVDS enabled on transcoder %c, should be disabled\n", |
pipe_name(pipe)); |
assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB); |
assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC); |
assert_pch_hdmi_disabled(dev_priv, pipe, HDMID); |
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); |
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); |
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); |
} |
/** |
1871,6 → 1898,7 |
* or we might hang the display. |
*/ |
assert_planes_disabled(dev_priv, pipe); |
assert_sprites_disabled(dev_priv, pipe); |
/* Don't disable pipe A or pipe A PLLs if needed */ |
if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) |
1949,6 → 1977,15 |
intel_wait_for_vblank(dev_priv->dev, pipe); |
} |
static bool need_vtd_wa(struct drm_device *dev) |
{ |
#ifdef CONFIG_INTEL_IOMMU |
if (INTEL_INFO(dev)->gen >= 6 && intel_iommu_gfx_mapped) |
return true; |
#endif |
return false; |
} |
int |
intel_pin_and_fence_fb_obj(struct drm_device *dev, |
struct drm_i915_gem_object *obj, |
1972,13 → 2009,23 |
alignment = 0; |
break; |
case I915_TILING_Y: |
/* FIXME: Is this true? */ |
DRM_ERROR("Y tiled not allowed for scan out buffers\n"); |
/* Despite that we check this in framebuffer_init userspace can |
* screw us over and change the tiling after the fact. Only |
* pinned buffers can't change their tiling. */ |
DRM_DEBUG_DRIVER("Y tiled not allowed for scan out buffers\n"); |
return -EINVAL; |
default: |
BUG(); |
} |
/* Note that the w/a also requires 64 PTE of padding following the |
* bo. We currently fill all unused PTE with the shadow page and so |
* we should always have valid PTE following the scanout preventing |
* the VT-d warning. |
*/ |
if (need_vtd_wa(dev) && alignment < 256 * 1024) |
alignment = 256 * 1024; |
dev_priv->mm.interruptible = false; |
ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined); |
if (ret) |
2095,8 → 2142,7 |
dspcntr |= DISPPLANE_RGBX101010; |
break; |
default: |
DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); |
return -EINVAL; |
BUG(); |
} |
if (INTEL_INFO(dev)->gen >= 4) { |
2189,8 → 2235,7 |
dspcntr |= DISPPLANE_RGBX101010; |
break; |
default: |
DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); |
return -EINVAL; |
BUG(); |
} |
if (obj->tiling_mode != I915_TILING_NONE) |
2282,10 → 2327,10 |
return 0; |
} |
if(intel_crtc->plane > dev_priv->num_pipe) { |
if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { |
DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n", |
intel_crtc->plane, |
dev_priv->num_pipe); |
INTEL_INFO(dev)->num_pipes); |
return -EINVAL; |
} |
2299,8 → 2344,6 |
// return ret; |
// } |
// if (crtc->fb) |
// intel_finish_fb(crtc->fb); |
ret = dev_priv->display.update_plane(crtc, fb, x, y); |
if (ret) { |
2899,32 → 2942,8 |
} |
#endif |
static bool ironlake_crtc_driving_pch(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct intel_encoder *intel_encoder; |
/* |
* If there's a non-PCH eDP on this crtc, it must be DP_A, and that |
* must be driven by its own crtc; no sharing is possible. |
*/ |
for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |
switch (intel_encoder->type) { |
case INTEL_OUTPUT_EDP: |
if (!intel_encoder_is_pch_edp(&intel_encoder->base)) |
return false; |
continue; |
} |
} |
return true; |
} |
static bool haswell_crtc_driving_pch(struct drm_crtc *crtc) |
{ |
return intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG); |
} |
/* Program iCLKIP clock to the desired frequency */ |
static void lpt_program_iclkip(struct drm_crtc *crtc) |
{ |
3131,7 → 3150,7 |
struct drm_device *dev = crtc->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
assert_transcoder_disabled(dev_priv, TRANSCODER_A); |
3260,7 → 3279,6 |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
u32 temp; |
bool is_pch_port; |
WARN_ON(!crtc->enabled); |
3276,9 → 3294,8 |
I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); |
} |
is_pch_port = ironlake_crtc_driving_pch(crtc); |
if (is_pch_port) { |
if (intel_crtc->config.has_pch_encoder) { |
/* Note: FDI PLL enabling _must_ be done before we enable the |
* cpu pipes, hence this is separate from all the other fdi/pch |
* enabling. */ |
3315,10 → 3332,11 |
*/ |
intel_crtc_load_lut(crtc); |
intel_enable_pipe(dev_priv, pipe, is_pch_port); |
intel_enable_pipe(dev_priv, pipe, |
intel_crtc->config.has_pch_encoder); |
intel_enable_plane(dev_priv, plane, pipe); |
if (is_pch_port) |
if (intel_crtc->config.has_pch_encoder) |
ironlake_pch_enable(crtc); |
mutex_lock(&dev->struct_mutex); |
3352,7 → 3370,6 |
struct intel_encoder *encoder; |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
bool is_pch_port; |
WARN_ON(!crtc->enabled); |
3362,9 → 3379,7 |
intel_crtc->active = true; |
intel_update_watermarks(dev); |
is_pch_port = haswell_crtc_driving_pch(crtc); |
if (is_pch_port) |
if (intel_crtc->config.has_pch_encoder) |
dev_priv->display.fdi_link_train(crtc); |
for_each_encoder_on_crtc(dev, crtc, encoder) |
3393,12 → 3408,13 |
intel_crtc_load_lut(crtc); |
intel_ddi_set_pipe_settings(crtc); |
intel_ddi_enable_pipe_func(crtc); |
intel_ddi_enable_transcoder_func(crtc); |
intel_enable_pipe(dev_priv, pipe, is_pch_port); |
intel_enable_pipe(dev_priv, pipe, |
intel_crtc->config.has_pch_encoder); |
intel_enable_plane(dev_priv, plane, pipe); |
if (is_pch_port) |
if (intel_crtc->config.has_pch_encoder) |
lpt_pch_enable(crtc); |
mutex_lock(&dev->struct_mutex); |
3509,14 → 3525,11 |
struct intel_encoder *encoder; |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
bool is_pch_port; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
if (!intel_crtc->active) |
return; |
is_pch_port = haswell_crtc_driving_pch(crtc); |
for_each_encoder_on_crtc(dev, crtc, encoder) |
encoder->disable(encoder); |
3530,9 → 3543,13 |
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); |
/* Disable PF */ |
/* XXX: Once we have proper panel fitter state tracking implemented with |
* hardware state read/check support we should switch to only disable |
* the panel fitter when we know it's used. */ |
if (intel_using_power_well(dev)) { |
I915_WRITE(PF_CTL(pipe), 0); |
I915_WRITE(PF_WIN_SZ(pipe), 0); |
} |
intel_ddi_disable_pipe_clock(intel_crtc); |
3540,7 → 3557,7 |
if (encoder->post_disable) |
encoder->post_disable(encoder); |
if (is_pch_port) { |
if (intel_crtc->config.has_pch_encoder) { |
lpt_disable_pch_transcoder(dev_priv); |
intel_ddi_fdi_disable(crtc); |
} |
3565,7 → 3582,7 |
/* Stop saying we're using TRANSCODER_EDP because some other CRTC might |
* start using it. */ |
intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe; |
intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe; |
intel_ddi_put_crtc_pll(crtc); |
} |
3651,6 → 3668,26 |
encoder->enable(encoder); |
} |
static void i9xx_pfit_disable(struct intel_crtc *crtc) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum pipe pipe; |
uint32_t pctl = I915_READ(PFIT_CONTROL); |
assert_pipe_disabled(dev_priv, crtc->pipe); |
if (INTEL_INFO(dev)->gen >= 4) |
pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT; |
else |
pipe = PIPE_B; |
if (pipe == crtc->pipe) { |
DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl); |
I915_WRITE(PFIT_CONTROL, 0); |
} |
} |
static void i9xx_crtc_disable(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
3659,9 → 3696,7 |
struct intel_encoder *encoder; |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
u32 pctl; |
if (!intel_crtc->active) |
return; |
3680,11 → 3715,7 |
intel_disable_plane(dev_priv, plane, pipe); |
intel_disable_pipe(dev_priv, pipe); |
/* Disable pannel fitter if it is on this pipe. */ |
pctl = I915_READ(PFIT_CONTROL); |
if ((pctl & PFIT_ENABLE) && |
((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe) |
I915_WRITE(PFIT_CONTROL, 0); |
i9xx_pfit_disable(intel_crtc); |
intel_disable_pll(dev_priv, pipe); |
3894,15 → 3925,16 |
return encoder->get_hw_state(encoder, &pipe); |
} |
static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static bool intel_crtc_compute_config(struct drm_crtc *crtc, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
if (HAS_PCH_SPLIT(dev)) { |
/* FDI link clock is fixed at 2.7G */ |
if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4) |
if (pipe_config->requested_mode.clock * 3 |
> IRONLAKE_FDI_FREQ * 4) |
return false; |
} |
3909,7 → 3941,7 |
/* All interlaced capable intel hw wants timings in frames. Note though |
* that intel_lvds_mode_fixup does some funny tricks with the crtc |
* timings, so we need to be careful not to clobber these.*/ |
if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET)) |
if (!pipe_config->timings_set) |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
/* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes |
3919,6 → 3951,14 |
adjusted_mode->hsync_start == adjusted_mode->hdisplay) |
return false; |
if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { |
pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ |
} else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) { |
/* only a 8bpc pipe, with 6bpc dither through the panel fitter |
* for lvds. */ |
pipe_config->pipe_bpp = 8*3; |
} |
return true; |
} |
3992,14 → 4032,23 |
} |
static void |
intel_reduce_ratio(uint32_t *num, uint32_t *den) |
intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) |
{ |
while (*num > 0xffffff || *den > 0xffffff) { |
while (*num > DATA_LINK_M_N_MASK || |
*den > DATA_LINK_M_N_MASK) { |
*num >>= 1; |
*den >>= 1; |
} |
} |
static void compute_m_n(unsigned int m, unsigned int n, |
uint32_t *ret_m, uint32_t *ret_n) |
{ |
*ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); |
*ret_m = div_u64((uint64_t) m * *ret_n, n); |
intel_reduce_m_n_ratio(ret_m, ret_n); |
} |
void |
intel_link_compute_m_n(int bits_per_pixel, int nlanes, |
int pixel_clock, int link_clock, |
4006,12 → 4055,13 |
struct intel_link_m_n *m_n) |
{ |
m_n->tu = 64; |
m_n->gmch_m = bits_per_pixel * pixel_clock; |
m_n->gmch_n = link_clock * nlanes * 8; |
intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); |
m_n->link_m = pixel_clock; |
m_n->link_n = link_clock; |
intel_reduce_ratio(&m_n->link_m, &m_n->link_n); |
compute_m_n(bits_per_pixel * pixel_clock, |
link_clock * nlanes * 8, |
&m_n->gmch_m, &m_n->gmch_n); |
compute_m_n(pixel_clock, link_clock, |
&m_n->link_m, &m_n->link_n); |
} |
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) |
4022,142 → 4072,6 |
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); |
} |
/** |
* intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send |
* @crtc: CRTC structure |
* @mode: requested mode |
* |
* A pipe may be connected to one or more outputs. Based on the depth of the |
* attached framebuffer, choose a good color depth to use on the pipe. |
* |
* If possible, match the pipe depth to the fb depth. In some cases, this |
* isn't ideal, because the connected output supports a lesser or restricted |
* set of depths. Resolve that here: |
* LVDS typically supports only 6bpc, so clamp down in that case |
* HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc |
* Displays may support a restricted set as well, check EDID and clamp as |
* appropriate. |
* DP may want to dither down to 6bpc to fit larger modes |
* |
* RETURNS: |
* Dithering requirement (i.e. false if display bpc and pipe bpc match, |
* true if they don't match). |
*/ |
static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, |
struct drm_framebuffer *fb, |
unsigned int *pipe_bpp, |
struct drm_display_mode *mode) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_connector *connector; |
struct intel_encoder *intel_encoder; |
unsigned int display_bpc = UINT_MAX, bpc; |
/* Walk the encoders & connectors on this crtc, get min bpc */ |
for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |
if (intel_encoder->type == INTEL_OUTPUT_LVDS) { |
unsigned int lvds_bpc; |
if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == |
LVDS_A3_POWER_UP) |
lvds_bpc = 8; |
else |
lvds_bpc = 6; |
if (lvds_bpc < display_bpc) { |
DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc); |
display_bpc = lvds_bpc; |
} |
continue; |
} |
/* Not one of the known troublemakers, check the EDID */ |
list_for_each_entry(connector, &dev->mode_config.connector_list, |
head) { |
if (connector->encoder != &intel_encoder->base) |
continue; |
/* Don't use an invalid EDID bpc value */ |
if (connector->display_info.bpc && |
connector->display_info.bpc < display_bpc) { |
DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); |
display_bpc = connector->display_info.bpc; |
} |
} |
if (intel_encoder->type == INTEL_OUTPUT_EDP) { |
/* Use VBT settings if we have an eDP panel */ |
unsigned int edp_bpc = dev_priv->edp.bpp / 3; |
if (edp_bpc && edp_bpc < display_bpc) { |
DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); |
display_bpc = edp_bpc; |
} |
continue; |
} |
/* |
* HDMI is either 12 or 8, so if the display lets 10bpc sneak |
* through, clamp it down. (Note: >12bpc will be caught below.) |
*/ |
if (intel_encoder->type == INTEL_OUTPUT_HDMI) { |
if (display_bpc > 8 && display_bpc < 12) { |
DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); |
display_bpc = 12; |
} else { |
DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); |
display_bpc = 8; |
} |
} |
} |
if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { |
DRM_DEBUG_KMS("Dithering DP to 6bpc\n"); |
display_bpc = 6; |
} |
/* |
* We could just drive the pipe at the highest bpc all the time and |
* enable dithering as needed, but that costs bandwidth. So choose |
* the minimum value that expresses the full color range of the fb but |
* also stays within the max display bpc discovered above. |
*/ |
switch (fb->depth) { |
case 8: |
bpc = 8; /* since we go through a colormap */ |
break; |
case 15: |
case 16: |
bpc = 6; /* min is 18bpp */ |
break; |
case 24: |
bpc = 8; |
break; |
case 30: |
bpc = 10; |
break; |
case 48: |
bpc = 12; |
break; |
default: |
DRM_DEBUG("unsupported depth, assuming 24 bits\n"); |
bpc = min((unsigned int)8, display_bpc); |
break; |
} |
display_bpc = min(display_bpc, bpc); |
DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n", |
bpc, display_bpc); |
*pipe_bpp = display_bpc * 3; |
return display_bpc != bpc; |
} |
static int vlv_get_refclk(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
4202,20 → 4116,20 |
return refclk; |
} |
static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode, |
intel_clock_t *clock) |
static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc) |
{ |
unsigned dotclock = crtc->config.adjusted_mode.clock; |
struct dpll *clock = &crtc->config.dpll; |
/* SDVO TV has fixed PLL values depend on its clock range, |
this mirrors vbios setting. */ |
if (adjusted_mode->clock >= 100000 |
&& adjusted_mode->clock < 140500) { |
if (dotclock >= 100000 && dotclock < 140500) { |
clock->p1 = 2; |
clock->p2 = 10; |
clock->n = 3; |
clock->m1 = 16; |
clock->m2 = 8; |
} else if (adjusted_mode->clock >= 140500 |
&& adjusted_mode->clock <= 200000) { |
} else if (dotclock >= 140500 && dotclock <= 200000) { |
clock->p1 = 1; |
clock->p2 = 10; |
clock->n = 6; |
4222,17 → 4136,18 |
clock->m1 = 12; |
clock->m2 = 8; |
} |
crtc->config.clock_set = true; |
} |
static void i9xx_update_pll_dividers(struct drm_crtc *crtc, |
intel_clock_t *clock, |
static void i9xx_update_pll_dividers(struct intel_crtc *crtc, |
intel_clock_t *reduced_clock) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
int pipe = intel_crtc->pipe; |
int pipe = crtc->pipe; |
u32 fp, fp2 = 0; |
struct dpll *clock = &crtc->config.dpll; |
if (IS_PINEVIEW(dev)) { |
fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2; |
4248,26 → 4163,29 |
I915_WRITE(FP0(pipe), fp); |
intel_crtc->lowfreq_avail = false; |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && |
crtc->lowfreq_avail = false; |
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && |
reduced_clock && i915_powersave) { |
I915_WRITE(FP1(pipe), fp2); |
intel_crtc->lowfreq_avail = true; |
crtc->lowfreq_avail = true; |
} else { |
I915_WRITE(FP1(pipe), fp); |
} |
} |
static void vlv_update_pll(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
intel_clock_t *clock, intel_clock_t *reduced_clock, |
int num_connectors) |
static void intel_dp_set_m_n(struct intel_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
if (crtc->config.has_pch_encoder) |
intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); |
else |
intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); |
} |
static void vlv_update_pll(struct intel_crtc *crtc) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
int pipe = intel_crtc->pipe; |
int pipe = crtc->pipe; |
u32 dpll, mdiv, pdiv; |
u32 bestn, bestm1, bestm2, bestp1, bestp2; |
bool is_sdvo; |
4275,8 → 4193,8 |
mutex_lock(&dev_priv->dpio_lock); |
is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || |
intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); |
is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || |
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); |
dpll = DPLL_VGA_MODE_DIS; |
dpll |= DPLL_EXT_BUFFER_ENABLE_VLV; |
4286,11 → 4204,11 |
I915_WRITE(DPLL(pipe), dpll); |
POSTING_READ(DPLL(pipe)); |
bestn = clock->n; |
bestm1 = clock->m1; |
bestm2 = clock->m2; |
bestp1 = clock->p1; |
bestp2 = clock->p2; |
bestn = crtc->config.dpll.n; |
bestm1 = crtc->config.dpll.m1; |
bestm2 = crtc->config.dpll.m2; |
bestp1 = crtc->config.dpll.p1; |
bestp2 = crtc->config.dpll.p2; |
/* |
* In Valleyview PLL and program lane counter registers are exposed |
4322,8 → 4240,8 |
intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620); |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) |
intel_dp_set_m_n(crtc, mode, adjusted_mode); |
if (crtc->config.has_dp_encoder) |
intel_dp_set_m_n(crtc); |
I915_WRITE(DPLL(pipe), dpll); |
4333,26 → 4251,25 |
temp = 0; |
if (is_sdvo) { |
temp = intel_mode_get_pixel_multiplier(adjusted_mode); |
if (temp > 1) |
temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; |
else |
temp = 0; |
if (crtc->config.pixel_multiplier > 1) { |
temp = (crtc->config.pixel_multiplier - 1) |
<< DPLL_MD_UDI_MULTIPLIER_SHIFT; |
} |
} |
I915_WRITE(DPLL_MD(pipe), temp); |
POSTING_READ(DPLL_MD(pipe)); |
/* Now program lane control registers */ |
if(intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) |
|| intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) |
{ |
if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) |
|| intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) { |
temp = 0x1000C4; |
if(pipe == 1) |
temp |= (1 << 21); |
intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp); |
} |
if(intel_pipe_has_type(crtc,INTEL_OUTPUT_EDP)) |
{ |
if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { |
temp = 0x1000C4; |
if(pipe == 1) |
temp |= (1 << 21); |
4362,40 → 4279,39 |
mutex_unlock(&dev_priv->dpio_lock); |
} |
static void i9xx_update_pll(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
intel_clock_t *clock, intel_clock_t *reduced_clock, |
static void i9xx_update_pll(struct intel_crtc *crtc, |
intel_clock_t *reduced_clock, |
int num_connectors) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_encoder *encoder; |
int pipe = intel_crtc->pipe; |
int pipe = crtc->pipe; |
u32 dpll; |
bool is_sdvo; |
struct dpll *clock = &crtc->config.dpll; |
i9xx_update_pll_dividers(crtc, clock, reduced_clock); |
i9xx_update_pll_dividers(crtc, reduced_clock); |
is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || |
intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); |
is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || |
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); |
dpll = DPLL_VGA_MODE_DIS; |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) |
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) |
dpll |= DPLLB_MODE_LVDS; |
else |
dpll |= DPLLB_MODE_DAC_SERIAL; |
if (is_sdvo) { |
int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); |
if (pixel_multiplier > 1) { |
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) |
dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; |
if ((crtc->config.pixel_multiplier > 1) && |
(IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) { |
dpll |= (crtc->config.pixel_multiplier - 1) |
<< SDVO_MULTIPLIER_SHIFT_HIRES; |
} |
dpll |= DPLL_DVO_HIGH_SPEED; |
} |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) |
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) |
dpll |= DPLL_DVO_HIGH_SPEED; |
/* compute bitmask from p1 value */ |
4423,13 → 4339,13 |
if (INTEL_INFO(dev)->gen >= 4) |
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); |
if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) |
if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) |
dpll |= PLL_REF_INPUT_TVCLKINBC; |
else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) |
else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) |
/* XXX: just matching BIOS for now */ |
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */ |
dpll |= 3; |
else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && |
else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && |
intel_panel_use_ssc(dev_priv) && num_connectors < 2) |
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; |
else |
4440,12 → 4356,12 |
POSTING_READ(DPLL(pipe)); |
udelay(150); |
for_each_encoder_on_crtc(dev, crtc, encoder) |
for_each_encoder_on_crtc(dev, &crtc->base, encoder) |
if (encoder->pre_pll_enable) |
encoder->pre_pll_enable(encoder); |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) |
intel_dp_set_m_n(crtc, mode, adjusted_mode); |
if (crtc->config.has_dp_encoder) |
intel_dp_set_m_n(crtc); |
I915_WRITE(DPLL(pipe), dpll); |
4456,12 → 4372,12 |
if (INTEL_INFO(dev)->gen >= 4) { |
u32 temp = 0; |
if (is_sdvo) { |
temp = intel_mode_get_pixel_multiplier(adjusted_mode); |
if (temp > 1) |
temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; |
else |
temp = 0; |
if (crtc->config.pixel_multiplier > 1) { |
temp = (crtc->config.pixel_multiplier - 1) |
<< DPLL_MD_UDI_MULTIPLIER_SHIFT; |
} |
} |
I915_WRITE(DPLL_MD(pipe), temp); |
} else { |
/* The pixel multiplier can only be updated once the |
4473,23 → 4389,23 |
} |
} |
static void i8xx_update_pll(struct drm_crtc *crtc, |
static void i8xx_update_pll(struct intel_crtc *crtc, |
struct drm_display_mode *adjusted_mode, |
intel_clock_t *clock, intel_clock_t *reduced_clock, |
intel_clock_t *reduced_clock, |
int num_connectors) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_encoder *encoder; |
int pipe = intel_crtc->pipe; |
int pipe = crtc->pipe; |
u32 dpll; |
struct dpll *clock = &crtc->config.dpll; |
i9xx_update_pll_dividers(crtc, clock, reduced_clock); |
i9xx_update_pll_dividers(crtc, reduced_clock); |
dpll = DPLL_VGA_MODE_DIS; |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) { |
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; |
} else { |
if (clock->p1 == 2) |
4500,11 → 4416,7 |
dpll |= PLL_P2_DIVIDE_BY_4; |
} |
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) |
/* XXX: just matching BIOS for now */ |
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */ |
dpll |= 3; |
else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && |
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && |
intel_panel_use_ssc(dev_priv) && num_connectors < 2) |
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; |
else |
4515,7 → 4427,7 |
POSTING_READ(DPLL(pipe)); |
udelay(150); |
for_each_encoder_on_crtc(dev, crtc, encoder) |
for_each_encoder_on_crtc(dev, &crtc->base, encoder) |
if (encoder->pre_pll_enable) |
encoder->pre_pll_enable(encoder); |
4540,7 → 4452,7 |
struct drm_device *dev = intel_crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum pipe pipe = intel_crtc->pipe; |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
uint32_t vsyncshift; |
if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { |
4591,9 → 4503,76 |
((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); |
} |
static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) |
{ |
struct drm_device *dev = intel_crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t pipeconf; |
pipeconf = I915_READ(PIPECONF(intel_crtc->pipe)); |
if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) { |
/* Enable pixel doubling when the dot clock is > 90% of the (display) |
* core speed. |
* |
* XXX: No double-wide on 915GM pipe B. Is that the only reason for the |
* pipe == 0 check? |
*/ |
if (intel_crtc->config.requested_mode.clock > |
dev_priv->display.get_display_clock_speed(dev) * 9 / 10) |
pipeconf |= PIPECONF_DOUBLE_WIDE; |
else |
pipeconf &= ~PIPECONF_DOUBLE_WIDE; |
} |
/* default to 8bpc */ |
pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); |
if (intel_crtc->config.has_dp_encoder) { |
if (intel_crtc->config.dither) { |
pipeconf |= PIPECONF_6BPC | |
PIPECONF_DITHER_EN | |
PIPECONF_DITHER_TYPE_SP; |
} |
} |
if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(&intel_crtc->base, |
INTEL_OUTPUT_EDP)) { |
if (intel_crtc->config.dither) { |
pipeconf |= PIPECONF_6BPC | |
PIPECONF_ENABLE | |
I965_PIPECONF_ACTIVE; |
} |
} |
if (HAS_PIPE_CXSR(dev)) { |
if (intel_crtc->lowfreq_avail) { |
DRM_DEBUG_KMS("enabling CxSR downclocking\n"); |
pipeconf |= PIPECONF_CXSR_DOWNCLOCK; |
} else { |
DRM_DEBUG_KMS("disabling CxSR downclocking\n"); |
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; |
} |
} |
pipeconf &= ~PIPECONF_INTERLACE_MASK; |
if (!IS_GEN2(dev) && |
intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) |
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; |
else |
pipeconf |= PIPECONF_PROGRESSIVE; |
if (IS_VALLEYVIEW(dev)) { |
if (intel_crtc->config.limited_color_range) |
pipeconf |= PIPECONF_COLOR_RANGE_SELECT; |
else |
pipeconf &= ~PIPECONF_COLOR_RANGE_SELECT; |
} |
I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf); |
POSTING_READ(PIPECONF(intel_crtc->pipe)); |
} |
static int i9xx_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, |
struct drm_framebuffer *fb) |
{ |
4600,13 → 4579,16 |
struct drm_device *dev = crtc->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
struct drm_display_mode *mode = &intel_crtc->config.requested_mode; |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
int refclk, num_connectors = 0; |
intel_clock_t clock, reduced_clock; |
u32 dspcntr, pipeconf; |
u32 dspcntr; |
bool ok, has_reduced_clock = false, is_sdvo = false; |
bool is_lvds = false, is_tv = false, is_dp = false; |
bool is_lvds = false, is_tv = false; |
struct intel_encoder *encoder; |
const intel_limit_t *limit; |
int ret; |
4625,9 → 4607,6 |
case INTEL_OUTPUT_TVOUT: |
is_tv = true; |
break; |
case INTEL_OUTPUT_DISPLAYPORT: |
is_dp = true; |
break; |
} |
num_connectors++; |
4664,86 → 4643,42 |
&clock, |
&reduced_clock); |
} |
/* Compat-code for transition, will disappear. */ |
if (!intel_crtc->config.clock_set) { |
intel_crtc->config.dpll.n = clock.n; |
intel_crtc->config.dpll.m1 = clock.m1; |
intel_crtc->config.dpll.m2 = clock.m2; |
intel_crtc->config.dpll.p1 = clock.p1; |
intel_crtc->config.dpll.p2 = clock.p2; |
} |
if (is_sdvo && is_tv) |
i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); |
i9xx_adjust_sdvo_tv_clock(intel_crtc); |
if (IS_GEN2(dev)) |
i8xx_update_pll(crtc, adjusted_mode, &clock, |
i8xx_update_pll(intel_crtc, adjusted_mode, |
has_reduced_clock ? &reduced_clock : NULL, |
num_connectors); |
else if (IS_VALLEYVIEW(dev)) |
vlv_update_pll(crtc, mode, adjusted_mode, &clock, |
has_reduced_clock ? &reduced_clock : NULL, |
num_connectors); |
vlv_update_pll(intel_crtc); |
else |
i9xx_update_pll(crtc, mode, adjusted_mode, &clock, |
i9xx_update_pll(intel_crtc, |
has_reduced_clock ? &reduced_clock : NULL, |
num_connectors); |
/* setup pipeconf */ |
pipeconf = I915_READ(PIPECONF(pipe)); |
/* Set up the display plane register */ |
dspcntr = DISPPLANE_GAMMA_ENABLE; |
if (!IS_VALLEYVIEW(dev)) { |
if (pipe == 0) |
dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; |
else |
dspcntr |= DISPPLANE_SEL_PIPE_B; |
if (pipe == 0 && INTEL_INFO(dev)->gen < 4) { |
/* Enable pixel doubling when the dot clock is > 90% of the (display) |
* core speed. |
* |
* XXX: No double-wide on 915GM pipe B. Is that the only reason for the |
* pipe == 0 check? |
*/ |
if (mode->clock > |
dev_priv->display.get_display_clock_speed(dev) * 9 / 10) |
pipeconf |= PIPECONF_DOUBLE_WIDE; |
else |
pipeconf &= ~PIPECONF_DOUBLE_WIDE; |
} |
/* default to 8bpc */ |
pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); |
if (is_dp) { |
if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { |
pipeconf |= PIPECONF_6BPC | |
PIPECONF_DITHER_EN | |
PIPECONF_DITHER_TYPE_SP; |
} |
} |
if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { |
if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { |
pipeconf |= PIPECONF_6BPC | |
PIPECONF_ENABLE | |
I965_PIPECONF_ACTIVE; |
} |
} |
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); |
drm_mode_debug_printmodeline(mode); |
if (HAS_PIPE_CXSR(dev)) { |
if (intel_crtc->lowfreq_avail) { |
DRM_DEBUG_KMS("enabling CxSR downclocking\n"); |
pipeconf |= PIPECONF_CXSR_DOWNCLOCK; |
} else { |
DRM_DEBUG_KMS("disabling CxSR downclocking\n"); |
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; |
} |
} |
pipeconf &= ~PIPECONF_INTERLACE_MASK; |
if (!IS_GEN2(dev) && |
adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) |
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; |
else |
pipeconf |= PIPECONF_PROGRESSIVE; |
intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); |
/* pipesrc and dspsize control the size that is scaled from, |
4754,8 → 4689,8 |
(mode->hdisplay - 1)); |
I915_WRITE(DSPPOS(plane), 0); |
I915_WRITE(PIPECONF(pipe), pipeconf); |
POSTING_READ(PIPECONF(pipe)); |
i9xx_set_pipeconf(intel_crtc); |
intel_enable_pipe(dev_priv, pipe, false); |
intel_wait_for_vblank(dev, pipe); |
4770,12 → 4705,26 |
return ret; |
} |
static bool i9xx_get_pipe_config(struct intel_crtc *crtc, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t tmp; |
tmp = I915_READ(PIPECONF(crtc->pipe)); |
if (!(tmp & PIPECONF_ENABLE)) |
return false; |
return true; |
} |
static void ironlake_init_pch_refclk(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_encoder *encoder; |
u32 temp; |
u32 val, final; |
bool has_lvds = false; |
bool has_cpu_edp = false; |
bool has_pch_edp = false; |
4818,70 → 4767,109 |
* PCH B stepping, previous chipset stepping should be |
* ignoring this setting. |
*/ |
temp = I915_READ(PCH_DREF_CONTROL); |
val = I915_READ(PCH_DREF_CONTROL); |
/* As we must carefully and slowly disable/enable each source in turn, |
* compute the final state we want first and check if we need to |
* make any changes at all. |
*/ |
final = val; |
final &= ~DREF_NONSPREAD_SOURCE_MASK; |
if (has_ck505) |
final |= DREF_NONSPREAD_CK505_ENABLE; |
else |
final |= DREF_NONSPREAD_SOURCE_ENABLE; |
final &= ~DREF_SSC_SOURCE_MASK; |
final &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
final &= ~DREF_SSC1_ENABLE; |
if (has_panel) { |
final |= DREF_SSC_SOURCE_ENABLE; |
if (intel_panel_use_ssc(dev_priv) && can_ssc) |
final |= DREF_SSC1_ENABLE; |
if (has_cpu_edp) { |
if (intel_panel_use_ssc(dev_priv) && can_ssc) |
final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; |
else |
final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; |
} else |
final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
} else { |
final |= DREF_SSC_SOURCE_DISABLE; |
final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
} |
if (final == val) |
return; |
/* Always enable nonspread source */ |
temp &= ~DREF_NONSPREAD_SOURCE_MASK; |
val &= ~DREF_NONSPREAD_SOURCE_MASK; |
if (has_ck505) |
temp |= DREF_NONSPREAD_CK505_ENABLE; |
val |= DREF_NONSPREAD_CK505_ENABLE; |
else |
temp |= DREF_NONSPREAD_SOURCE_ENABLE; |
val |= DREF_NONSPREAD_SOURCE_ENABLE; |
if (has_panel) { |
temp &= ~DREF_SSC_SOURCE_MASK; |
temp |= DREF_SSC_SOURCE_ENABLE; |
val &= ~DREF_SSC_SOURCE_MASK; |
val |= DREF_SSC_SOURCE_ENABLE; |
/* SSC must be turned on before enabling the CPU output */ |
if (intel_panel_use_ssc(dev_priv) && can_ssc) { |
DRM_DEBUG_KMS("Using SSC on panel\n"); |
temp |= DREF_SSC1_ENABLE; |
val |= DREF_SSC1_ENABLE; |
} else |
temp &= ~DREF_SSC1_ENABLE; |
val &= ~DREF_SSC1_ENABLE; |
/* Get SSC going before enabling the outputs */ |
I915_WRITE(PCH_DREF_CONTROL, temp); |
I915_WRITE(PCH_DREF_CONTROL, val); |
POSTING_READ(PCH_DREF_CONTROL); |
udelay(200); |
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
/* Enable CPU source on CPU attached eDP */ |
if (has_cpu_edp) { |
if (intel_panel_use_ssc(dev_priv) && can_ssc) { |
DRM_DEBUG_KMS("Using SSC on eDP\n"); |
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; |
val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; |
} |
else |
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; |
val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; |
} else |
temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
val |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
I915_WRITE(PCH_DREF_CONTROL, temp); |
I915_WRITE(PCH_DREF_CONTROL, val); |
POSTING_READ(PCH_DREF_CONTROL); |
udelay(200); |
} else { |
DRM_DEBUG_KMS("Disabling SSC entirely\n"); |
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
/* Turn off CPU output */ |
temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
val |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
I915_WRITE(PCH_DREF_CONTROL, temp); |
I915_WRITE(PCH_DREF_CONTROL, val); |
POSTING_READ(PCH_DREF_CONTROL); |
udelay(200); |
/* Turn off the SSC source */ |
temp &= ~DREF_SSC_SOURCE_MASK; |
temp |= DREF_SSC_SOURCE_DISABLE; |
val &= ~DREF_SSC_SOURCE_MASK; |
val |= DREF_SSC_SOURCE_DISABLE; |
/* Turn off SSC1 */ |
temp &= ~ DREF_SSC1_ENABLE; |
val &= ~DREF_SSC1_ENABLE; |
I915_WRITE(PCH_DREF_CONTROL, temp); |
I915_WRITE(PCH_DREF_CONTROL, val); |
POSTING_READ(PCH_DREF_CONTROL); |
udelay(200); |
} |
BUG_ON(val != final); |
} |
/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */ |
4946,13 → 4934,6 |
tmp |= (0x12 << 24); |
intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY); |
if (!is_sdv) { |
tmp = intel_sbi_read(dev_priv, 0x808C, SBI_MPHY); |
tmp &= ~(0x3 << 6); |
tmp |= (1 << 6) | (1 << 0); |
intel_sbi_write(dev_priv, 0x808C, tmp, SBI_MPHY); |
} |
if (is_sdv) { |
tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY); |
tmp |= 0x7FFF; |
5106,7 → 5087,7 |
val = I915_READ(PIPECONF(pipe)); |
val &= ~PIPECONF_BPC_MASK; |
switch (intel_crtc->bpp) { |
switch (intel_crtc->config.pipe_bpp) { |
case 18: |
val |= PIPECONF_6BPC; |
break; |
5134,7 → 5115,7 |
else |
val |= PIPECONF_PROGRESSIVE; |
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) |
if (intel_crtc->config.limited_color_range) |
val |= PIPECONF_COLOR_RANGE_SELECT; |
else |
val &= ~PIPECONF_COLOR_RANGE_SELECT; |
5150,8 → 5131,7 |
* is supported, but eventually this should handle various |
* RGB<->YCbCr scenarios as well. |
*/ |
static void intel_set_pipe_csc(struct drm_crtc *crtc, |
const struct drm_display_mode *adjusted_mode) |
static void intel_set_pipe_csc(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
5166,7 → 5146,7 |
* consideration. |
*/ |
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) |
if (intel_crtc->config.limited_color_range) |
coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */ |
/* |
5190,7 → 5170,7 |
if (INTEL_INFO(dev)->gen > 6) { |
uint16_t postoff = 0; |
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) |
if (intel_crtc->config.limited_color_range) |
postoff = (16 * (1 << 13) / 255) & 0x1fff; |
I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff); |
5201,7 → 5181,7 |
} else { |
uint32_t mode = CSC_MODE_YUV_TO_RGB; |
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) |
if (intel_crtc->config.limited_color_range) |
mode |= CSC_BLACK_SCREEN_OFFSET; |
I915_WRITE(PIPE_CSC_MODE(pipe), mode); |
5214,7 → 5194,7 |
{ |
struct drm_i915_private *dev_priv = crtc->dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
uint32_t val; |
val = I915_READ(PIPECONF(cpu_transcoder)); |
5291,7 → 5271,7 |
} |
if (is_sdvo && is_tv) |
i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock); |
i9xx_adjust_sdvo_tv_clock(to_intel_crtc(crtc)); |
return true; |
} |
5332,7 → 5312,7 |
return false; |
} |
if (dev_priv->num_pipe == 2) |
if (INTEL_INFO(dev)->num_pipes == 2) |
return true; |
switch (intel_crtc->pipe) { |
5389,41 → 5369,49 |
return bps / (link_bw * 8) + 1; |
} |
static void ironlake_set_m_n(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, |
struct intel_link_m_n *m_n) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
struct intel_encoder *intel_encoder, *edp_encoder = NULL; |
struct intel_link_m_n m_n = {0}; |
int target_clock, pixel_multiplier, lane, link_bw; |
bool is_dp = false, is_cpu_edp = false; |
int pipe = crtc->pipe; |
for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |
switch (intel_encoder->type) { |
case INTEL_OUTPUT_DISPLAYPORT: |
is_dp = true; |
break; |
case INTEL_OUTPUT_EDP: |
is_dp = true; |
if (!intel_encoder_is_pch_edp(&intel_encoder->base)) |
is_cpu_edp = true; |
edp_encoder = intel_encoder; |
break; |
I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); |
I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n); |
I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m); |
I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n); |
} |
void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, |
struct intel_link_m_n *m_n) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe = crtc->pipe; |
enum transcoder transcoder = crtc->config.cpu_transcoder; |
if (INTEL_INFO(dev)->gen >= 5) { |
I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m); |
I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n); |
I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); |
I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); |
} else { |
I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); |
I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n); |
I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m); |
I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n); |
} |
} |
/* FDI link */ |
pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); |
lane = 0; |
/* CPU eDP doesn't require FDI link, so just set DP M/N |
according to current link config */ |
if (is_cpu_edp) { |
intel_edp_link_config(edp_encoder, &lane, &link_bw); |
} else { |
static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
struct intel_link_m_n m_n = {0}; |
int target_clock, lane, link_bw; |
/* FDI is a binary signal running at ~2.7GHz, encoding |
* each output octet as 10 bits. The actual frequency |
* is stored as a divider into a 100MHz clock, and the |
5432,35 → 5420,28 |
* is: |
*/ |
link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; |
} |
/* [e]DP over FDI requires target mode clock instead of link clock. */ |
if (edp_encoder) |
target_clock = intel_edp_target_clock(edp_encoder, mode); |
else if (is_dp) |
target_clock = mode->clock; |
if (intel_crtc->config.pixel_target_clock) |
target_clock = intel_crtc->config.pixel_target_clock; |
else |
target_clock = adjusted_mode->clock; |
if (!lane) |
lane = ironlake_get_lanes_required(target_clock, link_bw, |
intel_crtc->bpp); |
intel_crtc->config.pipe_bpp); |
intel_crtc->fdi_lanes = lane; |
if (pixel_multiplier > 1) |
link_bw *= pixel_multiplier; |
intel_link_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n); |
if (intel_crtc->config.pixel_multiplier > 1) |
link_bw *= intel_crtc->config.pixel_multiplier; |
intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock, |
link_bw, &m_n); |
I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m); |
I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); |
I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m); |
I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n); |
intel_cpu_transcoder_set_m_n(intel_crtc, &m_n); |
} |
static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, |
struct drm_display_mode *adjusted_mode, |
intel_clock_t *clock, u32 fp) |
intel_clock_t *clock, u32 *fp, |
intel_clock_t *reduced_clock, u32 *fp2) |
{ |
struct drm_crtc *crtc = &intel_crtc->base; |
struct drm_device *dev = crtc->dev; |
5467,9 → 5448,8 |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_encoder *intel_encoder; |
uint32_t dpll; |
int factor, pixel_multiplier, num_connectors = 0; |
int factor, num_connectors = 0; |
bool is_lvds = false, is_sdvo = false, is_tv = false; |
bool is_dp = false, is_cpu_edp = false; |
for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |
switch (intel_encoder->type) { |
5485,14 → 5465,6 |
case INTEL_OUTPUT_TVOUT: |
is_tv = true; |
break; |
case INTEL_OUTPUT_DISPLAYPORT: |
is_dp = true; |
break; |
case INTEL_OUTPUT_EDP: |
is_dp = true; |
if (!intel_encoder_is_pch_edp(&intel_encoder->base)) |
is_cpu_edp = true; |
break; |
} |
num_connectors++; |
5503,14 → 5475,17 |
if (is_lvds) { |
if ((intel_panel_use_ssc(dev_priv) && |
dev_priv->lvds_ssc_freq == 100) || |
intel_is_dual_link_lvds(dev)) |
(HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) |
factor = 25; |
} else if (is_sdvo && is_tv) |
factor = 20; |
if (clock->m < factor * clock->n) |
fp |= FP_CB_TUNE; |
*fp |= FP_CB_TUNE; |
if (fp2 && (reduced_clock->m < factor * reduced_clock->n)) |
*fp2 |= FP_CB_TUNE; |
dpll = 0; |
if (is_lvds) |
5518,13 → 5493,14 |
else |
dpll |= DPLLB_MODE_DAC_SERIAL; |
if (is_sdvo) { |
pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); |
if (pixel_multiplier > 1) { |
dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; |
if (intel_crtc->config.pixel_multiplier > 1) { |
dpll |= (intel_crtc->config.pixel_multiplier - 1) |
<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; |
} |
dpll |= DPLL_DVO_HIGH_SPEED; |
} |
if (is_dp && !is_cpu_edp) |
if (intel_crtc->config.has_dp_encoder && |
intel_crtc->config.has_pch_encoder) |
dpll |= DPLL_DVO_HIGH_SPEED; |
/* compute bitmask from p1 value */ |
5562,8 → 5538,6 |
} |
static int ironlake_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, |
struct drm_framebuffer *fb) |
{ |
5570,6 → 5544,9 |
struct drm_device *dev = crtc->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
struct drm_display_mode *mode = &intel_crtc->config.requested_mode; |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
int num_connectors = 0; |
5576,7 → 5553,7 |
intel_clock_t clock, reduced_clock; |
u32 dpll, fp = 0, fp2 = 0; |
bool ok, has_reduced_clock = false; |
bool is_lvds = false, is_dp = false, is_cpu_edp = false; |
bool is_lvds = false; |
struct intel_encoder *encoder; |
int ret; |
bool dither, fdi_config_ok; |
5586,14 → 5563,6 |
case INTEL_OUTPUT_LVDS: |
is_lvds = true; |
break; |
case INTEL_OUTPUT_DISPLAYPORT: |
is_dp = true; |
break; |
case INTEL_OUTPUT_EDP: |
is_dp = true; |
if (!intel_encoder_is_pch_edp(&encoder->base)) |
is_cpu_edp = true; |
break; |
} |
num_connectors++; |
5602,6 → 5571,8 |
WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), |
"Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); |
intel_crtc->config.cpu_transcoder = pipe; |
ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, |
&has_reduced_clock, &reduced_clock); |
if (!ok) { |
5608,13 → 5579,20 |
DRM_ERROR("Couldn't find PLL settings for mode!\n"); |
return -EINVAL; |
} |
/* Compat-code for transition, will disappear. */ |
if (!intel_crtc->config.clock_set) { |
intel_crtc->config.dpll.n = clock.n; |
intel_crtc->config.dpll.m1 = clock.m1; |
intel_crtc->config.dpll.m2 = clock.m2; |
intel_crtc->config.dpll.p1 = clock.p1; |
intel_crtc->config.dpll.p2 = clock.p2; |
} |
/* Ensure that the cursor is valid for the new mode before changing... */ |
// intel_crtc_update_cursor(crtc, true); |
/* determine panel color depth */ |
dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, |
adjusted_mode); |
dither = intel_crtc->config.dither; |
if (is_lvds && dev_priv->lvds_dither) |
dither = true; |
5623,13 → 5601,14 |
fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | |
reduced_clock.m2; |
dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp); |
dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock, |
has_reduced_clock ? &fp2 : NULL); |
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); |
drm_mode_debug_printmodeline(mode); |
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ |
if (!is_cpu_edp) { |
if (intel_crtc->config.has_pch_encoder) { |
struct intel_pch_pll *pll; |
pll = intel_get_pch_pll(intel_crtc, dpll, fp); |
5641,8 → 5620,8 |
} else |
intel_put_pch_pll(intel_crtc); |
if (is_dp && !is_cpu_edp) |
intel_dp_set_m_n(crtc, mode, adjusted_mode); |
if (intel_crtc->config.has_dp_encoder) |
intel_dp_set_m_n(intel_crtc); |
for_each_encoder_on_crtc(dev, crtc, encoder) |
if (encoder->pre_pll_enable) |
5677,7 → 5656,9 |
/* Note, this also computes intel_crtc->fdi_lanes which is used below in |
* ironlake_check_fdi_lanes. */ |
ironlake_set_m_n(crtc, mode, adjusted_mode); |
intel_crtc->fdi_lanes = 0; |
if (intel_crtc->config.has_pch_encoder) |
ironlake_fdi_set_m_n(crtc); |
fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); |
5698,6 → 5679,23 |
return fdi_config_ok ? ret : -EINVAL; |
} |
static bool ironlake_get_pipe_config(struct intel_crtc *crtc, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t tmp; |
tmp = I915_READ(PIPECONF(crtc->pipe)); |
if (!(tmp & PIPECONF_ENABLE)) |
return false; |
if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE) |
pipe_config->has_pch_encoder = true; |
return true; |
} |
static void haswell_modeset_global_resources(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
5728,8 → 5726,6 |
} |
static int haswell_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, |
struct drm_framebuffer *fb) |
{ |
5736,10 → 5732,13 |
struct drm_device *dev = crtc->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
struct drm_display_mode *mode = &intel_crtc->config.requested_mode; |
int pipe = intel_crtc->pipe; |
int plane = intel_crtc->plane; |
int num_connectors = 0; |
bool is_dp = false, is_cpu_edp = false; |
bool is_cpu_edp = false; |
struct intel_encoder *encoder; |
int ret; |
bool dither; |
5746,11 → 5745,7 |
for_each_encoder_on_crtc(dev, crtc, encoder) { |
switch (encoder->type) { |
case INTEL_OUTPUT_DISPLAYPORT: |
is_dp = true; |
break; |
case INTEL_OUTPUT_EDP: |
is_dp = true; |
if (!intel_encoder_is_pch_edp(&encoder->base)) |
is_cpu_edp = true; |
break; |
5760,9 → 5755,9 |
} |
if (is_cpu_edp) |
intel_crtc->cpu_transcoder = TRANSCODER_EDP; |
intel_crtc->config.cpu_transcoder = TRANSCODER_EDP; |
else |
intel_crtc->cpu_transcoder = pipe; |
intel_crtc->config.cpu_transcoder = pipe; |
/* We are not sure yet this won't happen. */ |
WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", |
5771,7 → 5766,7 |
WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", |
num_connectors, pipe_name(pipe)); |
WARN_ON(I915_READ(PIPECONF(intel_crtc->cpu_transcoder)) & |
WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) & |
(PIPECONF_ENABLE | I965_PIPECONF_ACTIVE)); |
WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE); |
5783,25 → 5778,24 |
// intel_crtc_update_cursor(crtc, true); |
/* determine panel color depth */ |
dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, |
adjusted_mode); |
dither = intel_crtc->config.dither; |
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); |
drm_mode_debug_printmodeline(mode); |
if (is_dp && !is_cpu_edp) |
intel_dp_set_m_n(crtc, mode, adjusted_mode); |
if (intel_crtc->config.has_dp_encoder) |
intel_dp_set_m_n(intel_crtc); |
intel_crtc->lowfreq_avail = false; |
intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); |
if (!is_dp || is_cpu_edp) |
ironlake_set_m_n(crtc, mode, adjusted_mode); |
if (intel_crtc->config.has_pch_encoder) |
ironlake_fdi_set_m_n(crtc); |
haswell_set_pipeconf(crtc, adjusted_mode, dither); |
intel_set_pipe_csc(crtc, adjusted_mode); |
intel_set_pipe_csc(crtc); |
/* Set up the display plane register */ |
I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); |
5816,9 → 5810,32 |
return ret; |
} |
static bool haswell_get_pipe_config(struct intel_crtc *crtc, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t tmp; |
tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder)); |
if (!(tmp & PIPECONF_ENABLE)) |
return false; |
/* |
* aswell has only FDI/PCH transcoder A. It is which is connected to |
* DDI E. So just check whether this pipe is wired to DDI E and whether |
* the PCH transcoder is on. |
*/ |
tmp = I915_READ(TRANS_DDI_FUNC_CTL(crtc->pipe)); |
if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && |
I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) |
pipe_config->has_pch_encoder = true; |
return true; |
} |
static int intel_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
int x, int y, |
struct drm_framebuffer *fb) |
{ |
5827,13 → 5844,16 |
struct drm_encoder_helper_funcs *encoder_funcs; |
struct intel_encoder *encoder; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
struct drm_display_mode *mode = &intel_crtc->config.requested_mode; |
int pipe = intel_crtc->pipe; |
int ret; |
drm_vblank_pre_modeset(dev, pipe); |
ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, |
x, y, fb); |
ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb); |
drm_vblank_post_modeset(dev, pipe); |
if (ret != 0) |
5844,9 → 5864,13 |
encoder->base.base.id, |
drm_get_encoder_name(&encoder->base), |
mode->base.id, mode->name); |
if (encoder->mode_set) { |
encoder->mode_set(encoder); |
} else { |
encoder_funcs = encoder->base.helper_private; |
encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode); |
} |
} |
return 0; |
} |
6314,6 → 6338,8 |
/* we only need to pin inside GTT if cursor is non-phy */ |
mutex_lock(&dev->struct_mutex); |
if (!dev_priv->info->cursor_needs_physical) { |
unsigned alignment; |
if (obj->tiling_mode) { |
DRM_ERROR("cursor cannot be tiled\n"); |
ret = -EINVAL; |
6320,7 → 6346,16 |
goto fail_locked; |
} |
ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL); |
/* Note that the w/a also requires 2 PTE of padding following |
* the bo. We currently fill all unused PTE with the shadow |
* page and so we should always have valid PTE following the |
* cursor preventing the VT-d warning. |
*/ |
alignment = 0; |
if (need_vtd_wa(dev)) |
alignment = 64*1024; |
ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL); |
if (ret) { |
DRM_ERROR("failed to move cursor bo into the GTT\n"); |
goto fail_locked; |
6426,20 → 6461,6 |
intel_crtc_load_lut(crtc); |
} |
/** |
* 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 encoders. |
* |
* Currently this code will only succeed if there is a pipe with no encoders |
* 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, |
6766,7 → 6787,7 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
struct drm_display_mode *mode; |
int htot = I915_READ(HTOTAL(cpu_transcoder)); |
int hsync = I915_READ(HSYNC(cpu_transcoder)); |
6945,7 → 6966,6 |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_unpin_work *work; |
struct drm_i915_gem_object *obj; |
unsigned long flags; |
/* Ignore early vblank irqs */ |
6975,8 → 6995,6 |
spin_unlock_irqrestore(&dev->event_lock, flags); |
obj = work->old_fb_obj; |
wake_up_all(&dev_priv->pending_flip_queue); |
queue_work(dev_priv->wq, &work->work); |
7466,19 → 7484,93 |
} |
} |
static struct drm_display_mode * |
intel_modeset_adjusted_mode(struct drm_crtc *crtc, |
static int |
pipe_config_set_bpp(struct drm_crtc *crtc, |
struct drm_framebuffer *fb, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_connector *connector; |
int bpp; |
switch (fb->pixel_format) { |
case DRM_FORMAT_C8: |
bpp = 8*3; /* since we go through a colormap */ |
break; |
case DRM_FORMAT_XRGB1555: |
case DRM_FORMAT_ARGB1555: |
/* checked in intel_framebuffer_init already */ |
if (WARN_ON(INTEL_INFO(dev)->gen > 3)) |
return -EINVAL; |
case DRM_FORMAT_RGB565: |
bpp = 6*3; /* min is 18bpp */ |
break; |
case DRM_FORMAT_XBGR8888: |
case DRM_FORMAT_ABGR8888: |
/* checked in intel_framebuffer_init already */ |
if (WARN_ON(INTEL_INFO(dev)->gen < 4)) |
return -EINVAL; |
case DRM_FORMAT_XRGB8888: |
case DRM_FORMAT_ARGB8888: |
bpp = 8*3; |
break; |
case DRM_FORMAT_XRGB2101010: |
case DRM_FORMAT_ARGB2101010: |
case DRM_FORMAT_XBGR2101010: |
case DRM_FORMAT_ABGR2101010: |
/* checked in intel_framebuffer_init already */ |
if (WARN_ON(INTEL_INFO(dev)->gen < 4)) |
return -EINVAL; |
bpp = 10*3; |
break; |
/* TODO: gen4+ supports 16 bpc floating point, too. */ |
default: |
DRM_DEBUG_KMS("unsupported depth\n"); |
return -EINVAL; |
} |
pipe_config->pipe_bpp = bpp; |
/* Clamp display bpp to EDID value */ |
list_for_each_entry(connector, &dev->mode_config.connector_list, |
head) { |
if (connector->encoder && connector->encoder->crtc != crtc) |
continue; |
/* Don't use an invalid EDID bpc value */ |
if (connector->display_info.bpc && |
connector->display_info.bpc * 3 < bpp) { |
DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", |
bpp, connector->display_info.bpc*3); |
pipe_config->pipe_bpp = connector->display_info.bpc*3; |
} |
} |
return bpp; |
} |
static struct intel_crtc_config * |
intel_modeset_pipe_config(struct drm_crtc *crtc, |
struct drm_framebuffer *fb, |
struct drm_display_mode *mode) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_display_mode *adjusted_mode; |
struct drm_encoder_helper_funcs *encoder_funcs; |
struct intel_encoder *encoder; |
struct intel_crtc_config *pipe_config; |
int plane_bpp; |
adjusted_mode = drm_mode_duplicate(dev, mode); |
if (!adjusted_mode) |
pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); |
if (!pipe_config) |
return ERR_PTR(-ENOMEM); |
drm_mode_copy(&pipe_config->adjusted_mode, mode); |
drm_mode_copy(&pipe_config->requested_mode, mode); |
plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config); |
if (plane_bpp < 0) |
goto fail; |
/* Pass our mode to the connectors and the CRTC to give them a chance to |
* adjust it according to limitations or connector properties, and also |
* a chance to reject the mode entirely. |
7488,23 → 7580,38 |
if (&encoder->new_crtc->base != crtc) |
continue; |
if (encoder->compute_config) { |
if (!(encoder->compute_config(encoder, pipe_config))) { |
DRM_DEBUG_KMS("Encoder config failure\n"); |
goto fail; |
} |
continue; |
} |
encoder_funcs = encoder->base.helper_private; |
if (!(encoder_funcs->mode_fixup(&encoder->base, mode, |
adjusted_mode))) { |
if (!(encoder_funcs->mode_fixup(&encoder->base, |
&pipe_config->requested_mode, |
&pipe_config->adjusted_mode))) { |
DRM_DEBUG_KMS("Encoder fixup failed\n"); |
goto fail; |
} |
} |
if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) { |
if (!(intel_crtc_compute_config(crtc, pipe_config))) { |
DRM_DEBUG_KMS("CRTC fixup failed\n"); |
goto fail; |
} |
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
return adjusted_mode; |
pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; |
DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", |
plane_bpp, pipe_config->pipe_bpp, pipe_config->dither); |
return pipe_config; |
fail: |
drm_mode_destroy(dev, adjusted_mode); |
kfree(pipe_config); |
return ERR_PTR(-EINVAL); |
} |
7582,16 → 7689,11 |
if (crtc->enabled) |
*prepare_pipes |= 1 << intel_crtc->pipe; |
/* We only support modeset on one single crtc, hence we need to do that |
* only for the passed in crtc iff we change anything else than just |
* disable crtcs. |
* |
* This is actually not true, to be fully compatible with the old crtc |
* helper we automatically disable _any_ output (i.e. doesn't need to be |
* connected to the crtc we're modesetting on) if it's disconnected. |
* Which is a rather nutty api (since changed the output configuration |
* without userspace's explicit request can lead to confusion), but |
* alas. Hence we currently need to modeset on all pipes we prepare. */ |
/* |
* For simplicity do a full modeset on any pipe where the output routing |
* changed. We could be more clever, but that would require us to be |
* more careful with calling the relevant encoder->mode_set functions. |
*/ |
if (*prepare_pipes) |
*modeset_pipes = *prepare_pipes; |
7598,6 → 7700,14 |
/* ... and mask these out. */ |
*modeset_pipes &= ~(*disable_pipes); |
*prepare_pipes &= ~(*disable_pipes); |
/* |
* HACK: We don't (yet) fully support global modesets. intel_set_config |
* obies this rule, but the modeset restore mode of |
* intel_modeset_setup_hw_state does not. |
*/ |
*modeset_pipes &= 1 << intel_crtc->pipe; |
*prepare_pipes &= 1 << intel_crtc->pipe; |
} |
static bool intel_crtc_in_use(struct drm_crtc *crtc) |
7666,12 → 7776,29 |
base.head) \ |
if (mask & (1 <<(intel_crtc)->pipe)) \ |
static bool |
intel_pipe_config_compare(struct intel_crtc_config *current_config, |
struct intel_crtc_config *pipe_config) |
{ |
if (current_config->has_pch_encoder != pipe_config->has_pch_encoder) { |
DRM_ERROR("mismatch in has_pch_encoder " |
"(expected %i, found %i)\n", |
current_config->has_pch_encoder, |
pipe_config->has_pch_encoder); |
return false; |
} |
return true; |
} |
void |
intel_modeset_check_state(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct intel_crtc *crtc; |
struct intel_encoder *encoder; |
struct intel_connector *connector; |
struct intel_crtc_config pipe_config; |
list_for_each_entry(connector, &dev->mode_config.connector_list, |
base.head) { |
7760,17 → 7887,32 |
"crtc's computed enabled state doesn't match tracked enabled state " |
"(expected %i, found %i)\n", enabled, crtc->base.enabled); |
assert_pipe(dev->dev_private, crtc->pipe, crtc->active); |
memset(&pipe_config, 0, sizeof(pipe_config)); |
active = dev_priv->display.get_pipe_config(crtc, |
&pipe_config); |
/* hw state is inconsistent with the pipe A quirk */ |
if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) |
active = crtc->active; |
WARN(crtc->active != active, |
"crtc active state doesn't match with hw state " |
"(expected %i, found %i)\n", crtc->active, active); |
WARN(active && |
!intel_pipe_config_compare(&crtc->config, &pipe_config), |
"pipe state doesn't match!\n"); |
} |
} |
int intel_set_mode(struct drm_crtc *crtc, |
static int __intel_set_mode(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
int x, int y, struct drm_framebuffer *fb) |
{ |
struct drm_device *dev = crtc->dev; |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode; |
struct drm_display_mode *saved_mode, *saved_hwmode; |
struct intel_crtc_config *pipe_config = NULL; |
struct intel_crtc *intel_crtc; |
unsigned disable_pipes, prepare_pipes, modeset_pipes; |
int ret = 0; |
7783,12 → 7925,6 |
intel_modeset_affected_pipes(crtc, &modeset_pipes, |
&prepare_pipes, &disable_pipes); |
DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", |
modeset_pipes, prepare_pipes, disable_pipes); |
for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) |
intel_crtc_disable(&intel_crtc->base); |
*saved_hwmode = crtc->hwmode; |
*saved_mode = crtc->mode; |
7797,15 → 7933,22 |
* Hence simply check whether any bit is set in modeset_pipes in all the |
* pieces of code that are not yet converted to deal with mutliple crtcs |
* changing their mode at the same time. */ |
adjusted_mode = NULL; |
if (modeset_pipes) { |
adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); |
if (IS_ERR(adjusted_mode)) { |
ret = PTR_ERR(adjusted_mode); |
pipe_config = intel_modeset_pipe_config(crtc, fb, mode); |
if (IS_ERR(pipe_config)) { |
ret = PTR_ERR(pipe_config); |
pipe_config = NULL; |
goto out; |
} |
} |
DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", |
modeset_pipes, prepare_pipes, disable_pipes); |
for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) |
intel_crtc_disable(&intel_crtc->base); |
for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { |
if (intel_crtc->base.enabled) |
dev_priv->display.crtc_disable(&intel_crtc->base); |
7814,8 → 7957,14 |
/* crtc->mode is already used by the ->mode_set callbacks, hence we need |
* to set it here already despite that we pass it down the callchain. |
*/ |
if (modeset_pipes) |
if (modeset_pipes) { |
enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder; |
crtc->mode = *mode; |
/* mode_set/enable/disable functions rely on a correct pipe |
* config. */ |
to_intel_crtc(crtc)->config = *pipe_config; |
to_intel_crtc(crtc)->config.cpu_transcoder = tmp; |
} |
/* Only after disabling all output pipelines that will be changed can we |
* update the the output configuration. */ |
7829,7 → 7978,6 |
*/ |
for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { |
ret = intel_crtc_mode_set(&intel_crtc->base, |
mode, adjusted_mode, |
x, y, fb); |
if (ret) |
goto done; |
7841,7 → 7989,7 |
if (modeset_pipes) { |
/* Store real post-adjustment hardware mode. */ |
crtc->hwmode = *adjusted_mode; |
crtc->hwmode = pipe_config->adjusted_mode; |
/* Calculate and store various constants which |
* are later needed by vblank and swap-completion |
7852,19 → 8000,31 |
/* FIXME: add subpixel order */ |
done: |
drm_mode_destroy(dev, adjusted_mode); |
if (ret && crtc->enabled) { |
crtc->hwmode = *saved_hwmode; |
crtc->mode = *saved_mode; |
} else { |
intel_modeset_check_state(dev); |
} |
out: |
kfree(pipe_config); |
kfree(saved_mode); |
return ret; |
} |
int intel_set_mode(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
int x, int y, struct drm_framebuffer *fb) |
{ |
int ret; |
ret = __intel_set_mode(crtc, mode, x, y, fb); |
if (ret == 0) |
intel_modeset_check_state(crtc->dev); |
return ret; |
} |
void intel_crtc_restore_mode(struct drm_crtc *crtc) |
{ |
intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); |
7938,6 → 8098,21 |
} |
} |
static bool |
is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors, |
int num_connectors) |
{ |
int i; |
for (i = 0; i < num_connectors; i++) |
if (connectors[i].encoder && |
connectors[i].encoder->crtc == crtc && |
connectors[i].dpms != DRM_MODE_DPMS_ON) |
return true; |
return false; |
} |
static void |
intel_set_config_compute_mode_changes(struct drm_mode_set *set, |
struct intel_set_config *config) |
7945,7 → 8120,11 |
/* We should be able to check here if the fb has the same properties |
* and then just flip_or_move it */ |
if (set->crtc->fb != set->fb) { |
if (set->connectors != NULL && |
is_crtc_connector_off(set->crtc, *set->connectors, |
set->num_connectors)) { |
config->mode_changed = true; |
} else if (set->crtc->fb != set->fb) { |
/* If we have no fb then treat it as a full mode set */ |
if (set->crtc->fb == NULL) { |
DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); |
7952,14 → 8131,13 |
config->mode_changed = true; |
} else if (set->fb == NULL) { |
config->mode_changed = true; |
} else if (set->fb->depth != set->crtc->fb->depth) { |
} else if (set->fb->pixel_format != |
set->crtc->fb->pixel_format) { |
config->mode_changed = true; |
} else if (set->fb->bits_per_pixel != |
set->crtc->fb->bits_per_pixel) { |
config->mode_changed = true; |
} else |
} else { |
config->fb_changed = true; |
} |
} |
if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) |
config->fb_changed = true; |
8132,20 → 8310,16 |
ret = intel_set_mode(set->crtc, set->mode, |
set->x, set->y, set->fb); |
if (ret) { |
DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", |
set->crtc->base.id, ret); |
goto fail; |
} |
} else if (config->fb_changed) { |
// intel_crtc_wait_for_pending_flips(set->crtc); |
ret = intel_pipe_set_base(set->crtc, |
set->x, set->y, set->fb); |
} |
intel_set_config_free(config); |
return 0; |
if (ret) { |
DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", |
set->crtc->base.id, ret); |
fail: |
intel_set_config_restore_state(dev, config); |
8154,6 → 8328,7 |
intel_set_mode(save_set.crtc, save_set.mode, |
save_set.x, save_set.y, save_set.fb)) |
DRM_ERROR("failed to restore config after modeset failure\n"); |
} |
out_config: |
intel_set_config_free(config); |
8214,7 → 8389,7 |
/* Swap pipes & planes for FBC on pre-965 */ |
intel_crtc->pipe = pipe; |
intel_crtc->plane = pipe; |
intel_crtc->cpu_transcoder = pipe; |
intel_crtc->config.cpu_transcoder = pipe; |
if (IS_MOBILE(dev) && IS_GEN3(dev)) { |
DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); |
intel_crtc->plane = !pipe; |
8225,8 → 8400,6 |
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; |
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; |
intel_crtc->bpp = 24; /* default for pre-Ironlake */ |
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); |
} |
8307,7 → 8480,7 |
I915_WRITE(PFIT_CONTROL, 0); |
} |
if (!(HAS_DDI(dev) && (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) |
if (!IS_ULT(dev)) |
intel_crt_init(dev); |
if (HAS_DDI(dev)) { |
8336,20 → 8509,20 |
if (has_edp_a(dev)) |
intel_dp_init(dev, DP_A, PORT_A); |
if (I915_READ(HDMIB) & PORT_DETECTED) { |
if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) { |
/* PCH SDVOB multiplex with HDMIB */ |
found = intel_sdvo_init(dev, PCH_SDVOB, true); |
if (!found) |
intel_hdmi_init(dev, HDMIB, PORT_B); |
intel_hdmi_init(dev, PCH_HDMIB, PORT_B); |
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) |
intel_dp_init(dev, PCH_DP_B, PORT_B); |
} |
if (I915_READ(HDMIC) & PORT_DETECTED) |
intel_hdmi_init(dev, HDMIC, PORT_C); |
if (I915_READ(PCH_HDMIC) & SDVO_DETECTED) |
intel_hdmi_init(dev, PCH_HDMIC, PORT_C); |
if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED) |
intel_hdmi_init(dev, HDMID, PORT_D); |
if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED) |
intel_hdmi_init(dev, PCH_HDMID, PORT_D); |
if (I915_READ(PCH_DP_C) & DP_DETECTED) |
intel_dp_init(dev, PCH_DP_C, PORT_C); |
8361,24 → 8534,21 |
if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) |
intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); |
if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) { |
intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B); |
if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { |
intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, |
PORT_B); |
if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) |
intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); |
} |
if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED) |
intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C); |
} else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { |
bool found = false; |
if (I915_READ(SDVOB) & SDVO_DETECTED) { |
if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { |
DRM_DEBUG_KMS("probing SDVOB\n"); |
found = intel_sdvo_init(dev, SDVOB, true); |
found = intel_sdvo_init(dev, GEN3_SDVOB, true); |
if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { |
DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); |
intel_hdmi_init(dev, SDVOB, PORT_B); |
intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); |
} |
if (!found && SUPPORTS_INTEGRATED_DP(dev)) { |
8389,16 → 8559,16 |
/* Before G4X SDVOC doesn't have its own detect register */ |
if (I915_READ(SDVOB) & SDVO_DETECTED) { |
if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { |
DRM_DEBUG_KMS("probing SDVOC\n"); |
found = intel_sdvo_init(dev, SDVOC, false); |
found = intel_sdvo_init(dev, GEN3_SDVOC, false); |
} |
if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { |
if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { |
if (SUPPORTS_INTEGRATED_HDMI(dev)) { |
DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); |
intel_hdmi_init(dev, SDVOC, PORT_C); |
intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); |
} |
if (SUPPORTS_INTEGRATED_DP(dev)) { |
DRM_DEBUG_KMS("probing DP_C\n"); |
8533,8 → 8703,8 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
/* We always want a DPMS function */ |
if (HAS_DDI(dev)) { |
dev_priv->display.get_pipe_config = haswell_get_pipe_config; |
dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; |
dev_priv->display.crtc_enable = haswell_crtc_enable; |
dev_priv->display.crtc_disable = haswell_crtc_disable; |
8541,6 → 8711,7 |
dev_priv->display.off = haswell_crtc_off; |
dev_priv->display.update_plane = ironlake_update_plane; |
} else if (HAS_PCH_SPLIT(dev)) { |
dev_priv->display.get_pipe_config = ironlake_get_pipe_config; |
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; |
dev_priv->display.crtc_enable = ironlake_crtc_enable; |
dev_priv->display.crtc_disable = ironlake_crtc_disable; |
8547,6 → 8718,7 |
dev_priv->display.off = ironlake_crtc_off; |
dev_priv->display.update_plane = ironlake_update_plane; |
} else { |
dev_priv->display.get_pipe_config = i9xx_get_pipe_config; |
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; |
dev_priv->display.crtc_enable = i9xx_crtc_enable; |
dev_priv->display.crtc_disable = i9xx_crtc_disable; |
8771,7 → 8943,7 |
void intel_modeset_init(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int i, ret; |
int i, j, ret; |
drm_mode_config_init(dev); |
8787,6 → 8959,9 |
intel_init_pm(dev); |
if (INTEL_INFO(dev)->num_pipes == 0) |
return; |
intel_init_display(dev); |
if (IS_GEN2(dev)) { |
8802,14 → 8977,18 |
dev->mode_config.fb_base = dev_priv->gtt.mappable_base; |
DRM_DEBUG_KMS("%d display pipe%s available.\n", |
dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : ""); |
INTEL_INFO(dev)->num_pipes, |
INTEL_INFO(dev)->num_pipes > 1 ? "s" : ""); |
for (i = 0; i < dev_priv->num_pipe; i++) { |
for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { |
intel_crtc_init(dev, i); |
ret = intel_plane_init(dev, i); |
for (j = 0; j < dev_priv->num_plane; j++) { |
ret = intel_plane_init(dev, i, j); |
if (ret) |
DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret); |
DRM_DEBUG_KMS("pipe %d plane %d init failed: %d\n", |
i, j, ret); |
} |
} |
intel_cpu_pll_init(dev); |
intel_pch_pll_init(dev); |
8861,10 → 9040,11 |
static bool |
intel_check_plane_mapping(struct intel_crtc *crtc) |
{ |
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 reg, val; |
if (dev_priv->num_pipe == 1) |
if (INTEL_INFO(dev)->num_pipes == 1) |
return true; |
reg = DSPCNTR(!crtc->plane); |
8884,7 → 9064,7 |
u32 reg; |
/* Clear any frame start delays used for debugging left by the BIOS */ |
reg = PIPECONF(crtc->cpu_transcoder); |
reg = PIPECONF(crtc->config.cpu_transcoder); |
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); |
/* We need to sanitize the plane -> pipe mapping first because this will |
9001,6 → 9181,17 |
* the crtc fixup. */ |
} |
void i915_redisable_vga(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 vga_reg = i915_vgacntrl_reg(dev); |
if (I915_READ(vga_reg) != VGA_DISP_DISABLE) { |
DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); |
i915_disable_vga(dev); |
} |
} |
/* Scan out the current hw modeset state, sanitizes it and maps it into the drm |
* and i915 state tracking structures. */ |
void intel_modeset_setup_hw_state(struct drm_device *dev, |
9009,6 → 9200,7 |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum pipe pipe; |
u32 tmp; |
struct drm_plane *plane; |
struct intel_crtc *crtc; |
struct intel_encoder *encoder; |
struct intel_connector *connector; |
9028,10 → 9220,17 |
case TRANS_DDI_EDP_INPUT_C_ONOFF: |
pipe = PIPE_C; |
break; |
default: |
/* A bogus value has been programmed, disable |
* the transcoder */ |
WARN(1, "Bogus eDP source %08x\n", tmp); |
intel_ddi_disable_transcoder_func(dev_priv, |
TRANSCODER_EDP); |
goto setup_pipes; |
} |
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
crtc->cpu_transcoder = TRANSCODER_EDP; |
crtc->config.cpu_transcoder = TRANSCODER_EDP; |
DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n", |
pipe_name(pipe)); |
9038,14 → 9237,15 |
} |
} |
for_each_pipe(pipe) { |
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
setup_pipes: |
list_for_each_entry(crtc, &dev->mode_config.crtc_list, |
base.head) { |
enum transcoder tmp = crtc->config.cpu_transcoder; |
memset(&crtc->config, 0, sizeof(crtc->config)); |
crtc->config.cpu_transcoder = tmp; |
tmp = I915_READ(PIPECONF(crtc->cpu_transcoder)); |
if (tmp & PIPECONF_ENABLE) |
crtc->active = true; |
else |
crtc->active = false; |
crtc->active = dev_priv->display.get_pipe_config(crtc, |
&crtc->config); |
crtc->base.enabled = crtc->active; |
9104,11 → 9304,21 |
} |
if (force_restore) { |
/* |
* We need to use raw interfaces for restoring state to avoid |
* checking (bogus) intermediate states. |
*/ |
for_each_pipe(pipe) { |
intel_crtc_restore_mode(dev_priv->pipe_to_crtc_mapping[pipe]); |
struct drm_crtc *crtc = |
dev_priv->pipe_to_crtc_mapping[pipe]; |
__intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, |
crtc->fb); |
} |
list_for_each_entry(plane, &dev->mode_config.plane_list, head) |
intel_plane_restore(plane); |
// i915_redisable_vga(dev); |
i915_redisable_vga(dev); |
} else { |
intel_modeset_update_staged_output_state(dev); |
} |
9255,14 → 9465,23 |
for_each_pipe(i) { |
cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i); |
if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { |
error->cursor[i].control = I915_READ(CURCNTR(i)); |
error->cursor[i].position = I915_READ(CURPOS(i)); |
error->cursor[i].base = I915_READ(CURBASE(i)); |
} else { |
error->cursor[i].control = I915_READ(CURCNTR_IVB(i)); |
error->cursor[i].position = I915_READ(CURPOS_IVB(i)); |
error->cursor[i].base = I915_READ(CURBASE_IVB(i)); |
} |
error->plane[i].control = I915_READ(DSPCNTR(i)); |
error->plane[i].stride = I915_READ(DSPSTRIDE(i)); |
if (INTEL_INFO(dev)->gen <= 3) { |
error->plane[i].size = I915_READ(DSPSIZE(i)); |
error->plane[i].pos = I915_READ(DSPPOS(i)); |
} |
if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) |
error->plane[i].addr = I915_READ(DSPADDR(i)); |
if (INTEL_INFO(dev)->gen >= 4) { |
error->plane[i].surface = I915_READ(DSPSURF(i)); |
9287,10 → 9506,9 |
struct drm_device *dev, |
struct intel_display_error_state *error) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
int i; |
seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe); |
seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); |
for_each_pipe(i) { |
seq_printf(m, "Pipe [%d]:\n", i); |
seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); |
9305,8 → 9523,11 |
seq_printf(m, "Plane [%d]:\n", i); |
seq_printf(m, " CNTR: %08x\n", error->plane[i].control); |
seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); |
if (INTEL_INFO(dev)->gen <= 3) { |
seq_printf(m, " SIZE: %08x\n", error->plane[i].size); |
seq_printf(m, " POS: %08x\n", error->plane[i].pos); |
} |
if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) |
seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); |
if (INTEL_INFO(dev)->gen >= 4) { |
seq_printf(m, " SURF: %08x\n", error->plane[i].surface); |
/drivers/video/drm/i915/intel_dp.c |
---|
109,29 → 109,6 |
static void intel_dp_link_down(struct intel_dp *intel_dp); |
void |
intel_edp_link_config(struct intel_encoder *intel_encoder, |
int *lane_num, int *link_bw) |
{ |
struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); |
*lane_num = intel_dp->lane_count; |
*link_bw = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); |
} |
int |
intel_edp_target_clock(struct intel_encoder *intel_encoder, |
struct drm_display_mode *mode) |
{ |
struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); |
struct intel_connector *intel_connector = intel_dp->attached_connector; |
if (intel_connector->panel.fixed_mode) |
return intel_connector->panel.fixed_mode->clock; |
else |
return mode->clock; |
} |
static int |
intel_dp_max_link_bw(struct intel_dp *intel_dp) |
{ |
177,34 → 154,6 |
return (max_link_clock * max_lanes * 8) / 10; |
} |
static bool |
intel_dp_adjust_dithering(struct intel_dp *intel_dp, |
struct drm_display_mode *mode, |
bool adjust_mode) |
{ |
int max_link_clock = |
drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); |
int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); |
int max_rate, mode_rate; |
mode_rate = intel_dp_link_required(mode->clock, 24); |
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); |
if (mode_rate > max_rate) { |
mode_rate = intel_dp_link_required(mode->clock, 18); |
if (mode_rate > max_rate) |
return false; |
if (adjust_mode) |
mode->private_flags |
|= INTEL_MODE_DP_FORCE_6BPC; |
return true; |
} |
return true; |
} |
static int |
intel_dp_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
212,6 → 161,8 |
struct intel_dp *intel_dp = intel_attached_dp(connector); |
struct intel_connector *intel_connector = to_intel_connector(connector); |
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; |
int target_clock = mode->clock; |
int max_rate, mode_rate, max_lanes, max_link_clock; |
if (is_edp(intel_dp) && fixed_mode) { |
if (mode->hdisplay > fixed_mode->hdisplay) |
219,9 → 170,17 |
if (mode->vdisplay > fixed_mode->vdisplay) |
return MODE_PANEL; |
target_clock = fixed_mode->clock; |
} |
if (!intel_dp_adjust_dithering(intel_dp, mode, false)) |
max_link_clock = drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); |
max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); |
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); |
mode_rate = intel_dp_link_required(target_clock, 18); |
if (mode_rate > max_rate) |
return MODE_CLOCK_HIGH; |
if (mode->clock < 10000) |
294,8 → 253,10 |
{ |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp_stat_reg; |
return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0; |
pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; |
return (I915_READ(pp_stat_reg) & PP_ON) != 0; |
} |
static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) |
302,8 → 263,10 |
{ |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp_ctrl_reg; |
return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0; |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
return (I915_READ(pp_ctrl_reg) & EDP_FORCE_VDD) != 0; |
} |
static void |
311,14 → 274,19 |
{ |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp_stat_reg, pp_ctrl_reg; |
if (!is_edp(intel_dp)) |
return; |
pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { |
WARN(1, "eDP powered off while attempting aux channel communication.\n"); |
DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", |
I915_READ(PCH_PP_STATUS), |
I915_READ(PCH_PP_CONTROL)); |
I915_READ(pp_stat_reg), |
I915_READ(pp_ctrl_reg)); |
} |
} |
328,29 → 296,10 |
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); |
struct drm_device *dev = intel_dig_port->base.base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t ch_ctl = intel_dp->output_reg + 0x10; |
uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; |
uint32_t status; |
bool done; |
if (IS_HASWELL(dev)) { |
switch (intel_dig_port->port) { |
case PORT_A: |
ch_ctl = DPA_AUX_CH_CTL; |
break; |
case PORT_B: |
ch_ctl = PCH_DPB_AUX_CH_CTL; |
break; |
case PORT_C: |
ch_ctl = PCH_DPC_AUX_CH_CTL; |
break; |
case PORT_D: |
ch_ctl = PCH_DPD_AUX_CH_CTL; |
break; |
default: |
BUG(); |
} |
} |
#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) |
if (has_aux_irq) |
done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, |
370,11 → 319,10 |
uint8_t *send, int send_bytes, |
uint8_t *recv, int recv_size) |
{ |
uint32_t output_reg = intel_dp->output_reg; |
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); |
struct drm_device *dev = intel_dig_port->base.base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t ch_ctl = output_reg + 0x10; |
uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; |
uint32_t ch_data = ch_ctl + 4; |
int i, ret, recv_bytes; |
uint32_t status; |
388,29 → 336,6 |
*/ |
// pm_qos_update_request(&dev_priv->pm_qos, 0); |
if (IS_HASWELL(dev)) { |
switch (intel_dig_port->port) { |
case PORT_A: |
ch_ctl = DPA_AUX_CH_CTL; |
ch_data = DPA_AUX_CH_DATA1; |
break; |
case PORT_B: |
ch_ctl = PCH_DPB_AUX_CH_CTL; |
ch_data = PCH_DPB_AUX_CH_DATA1; |
break; |
case PORT_C: |
ch_ctl = PCH_DPC_AUX_CH_CTL; |
ch_data = PCH_DPC_AUX_CH_DATA1; |
break; |
case PORT_D: |
ch_ctl = PCH_DPD_AUX_CH_CTL; |
ch_data = PCH_DPD_AUX_CH_DATA1; |
break; |
default: |
BUG(); |
} |
} |
intel_dp_check_edp(intel_dp); |
/* The clock divider is based off the hrawclk, |
* and would like to run at 2MHz. So, take the |
428,10 → 353,14 |
aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ |
else |
aux_clock_divider = 225; /* eDP input clock at 450Mhz */ |
} else if (HAS_PCH_SPLIT(dev)) |
} else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { |
/* Workaround for non-ULT HSW */ |
aux_clock_divider = 74; |
} else if (HAS_PCH_SPLIT(dev)) { |
aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2); |
else |
} else { |
aux_clock_divider = intel_hrawclk(dev) / 2; |
} |
if (IS_GEN6(dev)) |
precharge = 3; |
732,12 → 661,14 |
} |
bool |
intel_dp_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
intel_dp_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = encoder->dev; |
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
struct drm_display_mode *mode = &pipe_config->requested_mode; |
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
struct intel_connector *intel_connector = intel_dp->attached_connector; |
int lane_count, clock; |
int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); |
744,7 → 675,13 |
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; |
int bpp, mode_rate; |
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; |
int target_clock, link_avail, link_clock; |
if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp)) |
pipe_config->has_pch_encoder = true; |
pipe_config->has_dp_encoder = true; |
if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { |
intel_fixed_panel_mode(intel_connector->panel.fixed_mode, |
adjusted_mode); |
752,6 → 689,8 |
intel_connector->panel.fitting_mode, |
mode, adjusted_mode); |
} |
/* We need to take the panel's fixed mode into account. */ |
target_clock = adjusted_mode->clock; |
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) |
return false; |
760,11 → 699,31 |
"max bw %02x pixel clock %iKHz\n", |
max_lane_count, bws[max_clock], adjusted_mode->clock); |
if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, true)) |
/* Walk through all bpp values. Luckily they're all nicely spaced with 2 |
* bpc in between. */ |
bpp = min_t(int, 8*3, pipe_config->pipe_bpp); |
if (is_edp(intel_dp) && dev_priv->edp.bpp) |
bpp = min_t(int, bpp, dev_priv->edp.bpp); |
for (; bpp >= 6*3; bpp -= 2*3) { |
mode_rate = intel_dp_link_required(target_clock, bpp); |
for (clock = 0; clock <= max_clock; clock++) { |
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { |
link_clock = drm_dp_bw_code_to_link_rate(bws[clock]); |
link_avail = intel_dp_max_data_rate(link_clock, |
lane_count); |
if (mode_rate <= link_avail) { |
goto found; |
} |
} |
} |
} |
return false; |
bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; |
found: |
if (intel_dp->color_range_auto) { |
/* |
* See: |
778,106 → 737,27 |
} |
if (intel_dp->color_range) |
adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; |
pipe_config->limited_color_range = true; |
mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); |
for (clock = 0; clock <= max_clock; clock++) { |
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { |
int link_bw_clock = |
drm_dp_bw_code_to_link_rate(bws[clock]); |
int link_avail = intel_dp_max_data_rate(link_bw_clock, |
lane_count); |
if (mode_rate <= link_avail) { |
intel_dp->link_bw = bws[clock]; |
intel_dp->lane_count = lane_count; |
adjusted_mode->clock = link_bw_clock; |
DRM_DEBUG_KMS("DP link bw %02x lane " |
"count %d clock %d bpp %d\n", |
adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); |
pipe_config->pipe_bpp = bpp; |
pipe_config->pixel_target_clock = target_clock; |
DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n", |
intel_dp->link_bw, intel_dp->lane_count, |
adjusted_mode->clock, bpp); |
DRM_DEBUG_KMS("DP link bw required %i available %i\n", |
mode_rate, link_avail); |
return true; |
} |
} |
} |
return false; |
} |
intel_link_compute_m_n(bpp, lane_count, |
target_clock, adjusted_mode->clock, |
&pipe_config->dp_m_n); |
void |
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_device *dev = crtc->dev; |
struct intel_encoder *intel_encoder; |
struct intel_dp *intel_dp; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
int lane_count = 4; |
struct intel_link_m_n m_n; |
int pipe = intel_crtc->pipe; |
enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
int target_clock; |
/* |
* Find the lane count in the intel_encoder private |
*/ |
for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |
intel_dp = enc_to_intel_dp(&intel_encoder->base); |
if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || |
intel_encoder->type == INTEL_OUTPUT_EDP) |
{ |
lane_count = intel_dp->lane_count; |
break; |
return true; |
} |
} |
target_clock = mode->clock; |
for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |
if (intel_encoder->type == INTEL_OUTPUT_EDP) { |
target_clock = intel_edp_target_clock(intel_encoder, |
mode); |
break; |
} |
} |
/* |
* Compute the GMCH and Link ratios. The '3' here is |
* the number of bytes_per_pixel post-LUT, which we always |
* set up for 8-bits of R/G/B, or 3 bytes total. |
*/ |
intel_link_compute_m_n(intel_crtc->bpp, lane_count, |
target_clock, adjusted_mode->clock, &m_n); |
if (IS_HASWELL(dev)) { |
I915_WRITE(PIPE_DATA_M1(cpu_transcoder), |
TU_SIZE(m_n.tu) | m_n.gmch_m); |
I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); |
I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m); |
I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n); |
} else if (HAS_PCH_SPLIT(dev)) { |
I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); |
I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n); |
I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m); |
I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n); |
} else if (IS_VALLEYVIEW(dev)) { |
I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); |
I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); |
I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); |
I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); |
} else { |
I915_WRITE(PIPE_GMCH_DATA_M(pipe), |
TU_SIZE(m_n.tu) | m_n.gmch_m); |
I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n); |
I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m); |
I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n); |
} |
} |
void intel_dp_init_link_config(struct intel_dp *intel_dp) |
{ |
memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); |
994,7 → 874,7 |
else |
intel_dp->DP |= DP_PLL_FREQ_270MHZ; |
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { |
if (!HAS_PCH_SPLIT(dev)) |
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) |
intel_dp->DP |= intel_dp->color_range; |
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
1009,7 → 889,7 |
if (intel_crtc->pipe == 1) |
intel_dp->DP |= DP_PIPEB_SELECT; |
if (is_cpu_edp(intel_dp)) { |
if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { |
/* don't miss out required setting for eDP */ |
if (adjusted_mode->clock < 200000) |
intel_dp->DP |= DP_PLL_FREQ_160MHZ; |
1020,7 → 900,7 |
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; |
} |
if (is_cpu_edp(intel_dp)) |
if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) |
ironlake_set_pll_edp(crtc, adjusted_mode->clock); |
} |
1039,16 → 919,20 |
{ |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp_stat_reg, pp_ctrl_reg; |
pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n", |
mask, value, |
I915_READ(PCH_PP_STATUS), |
I915_READ(PCH_PP_CONTROL)); |
I915_READ(pp_stat_reg), |
I915_READ(pp_ctrl_reg)); |
if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) { |
if (_wait_for((I915_READ(pp_stat_reg) & mask) == value, 5000, 10)) { |
DRM_ERROR("Panel status timeout: status %08x control %08x\n", |
I915_READ(PCH_PP_STATUS), |
I915_READ(PCH_PP_CONTROL)); |
I915_READ(pp_stat_reg), |
I915_READ(pp_ctrl_reg)); |
} |
} |
1075,10 → 959,16 |
* is locked |
*/ |
static u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv) |
static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) |
{ |
u32 control = I915_READ(PCH_PP_CONTROL); |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 control; |
u32 pp_ctrl_reg; |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
control = I915_READ(pp_ctrl_reg); |
control &= ~PANEL_UNLOCK_MASK; |
control |= PANEL_UNLOCK_REGS; |
return control; |
1089,6 → 979,7 |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp; |
u32 pp_stat_reg, pp_ctrl_reg; |
if (!is_edp(intel_dp)) |
return; |
1107,13 → 998,16 |
if (!ironlake_edp_have_panel_power(intel_dp)) |
ironlake_wait_panel_power_cycle(intel_dp); |
pp = ironlake_get_pp_control(dev_priv); |
pp = ironlake_get_pp_control(intel_dp); |
pp |= EDP_FORCE_VDD; |
I915_WRITE(PCH_PP_CONTROL, pp); |
POSTING_READ(PCH_PP_CONTROL); |
DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", |
I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); |
pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
I915_WRITE(pp_ctrl_reg, pp); |
POSTING_READ(pp_ctrl_reg); |
DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", |
I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); |
/* |
* If the panel wasn't on, delay before accessing aux channel |
*/ |
1128,19 → 1022,23 |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp; |
u32 pp_stat_reg, pp_ctrl_reg; |
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { |
pp = ironlake_get_pp_control(dev_priv); |
pp = ironlake_get_pp_control(intel_dp); |
pp &= ~EDP_FORCE_VDD; |
I915_WRITE(PCH_PP_CONTROL, pp); |
POSTING_READ(PCH_PP_CONTROL); |
pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
I915_WRITE(pp_ctrl_reg, pp); |
POSTING_READ(pp_ctrl_reg); |
/* Make sure sequencer is idle before allowing subsequent activity */ |
DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", |
I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); |
DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", |
I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); |
msleep(intel_dp->panel_power_down_delay); |
} |
} |
1184,6 → 1082,7 |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp; |
u32 pp_ctrl_reg; |
if (!is_edp(intel_dp)) |
return; |
1197,7 → 1096,7 |
ironlake_wait_panel_power_cycle(intel_dp); |
pp = ironlake_get_pp_control(dev_priv); |
pp = ironlake_get_pp_control(intel_dp); |
if (IS_GEN5(dev)) { |
/* ILK workaround: disable reset around power sequence */ |
pp &= ~PANEL_POWER_RESET; |
1209,9 → 1108,11 |
if (!IS_GEN5(dev)) |
pp |= PANEL_POWER_RESET; |
I915_WRITE(PCH_PP_CONTROL, pp); |
POSTING_READ(PCH_PP_CONTROL); |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
I915_WRITE(pp_ctrl_reg, pp); |
POSTING_READ(pp_ctrl_reg); |
ironlake_wait_panel_on(intel_dp); |
if (IS_GEN5(dev)) { |
1226,6 → 1127,7 |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp; |
u32 pp_ctrl_reg; |
if (!is_edp(intel_dp)) |
return; |
1234,13 → 1136,16 |
WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); |
pp = ironlake_get_pp_control(dev_priv); |
pp = ironlake_get_pp_control(intel_dp); |
/* We need to switch off panel power _and_ force vdd, for otherwise some |
* panels get very unhappy and cease to work. */ |
pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); |
I915_WRITE(PCH_PP_CONTROL, pp); |
POSTING_READ(PCH_PP_CONTROL); |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
I915_WRITE(pp_ctrl_reg, pp); |
POSTING_READ(pp_ctrl_reg); |
intel_dp->want_panel_vdd = false; |
ironlake_wait_panel_off(intel_dp); |
1253,6 → 1158,7 |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe; |
u32 pp; |
u32 pp_ctrl_reg; |
if (!is_edp(intel_dp)) |
return; |
1265,11 → 1171,14 |
* allowing it to appear. |
*/ |
msleep(intel_dp->backlight_on_delay); |
pp = ironlake_get_pp_control(dev_priv); |
pp = ironlake_get_pp_control(intel_dp); |
pp |= EDP_BLC_ENABLE; |
I915_WRITE(PCH_PP_CONTROL, pp); |
POSTING_READ(PCH_PP_CONTROL); |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
I915_WRITE(pp_ctrl_reg, pp); |
POSTING_READ(pp_ctrl_reg); |
intel_panel_enable_backlight(dev, pipe); |
} |
1278,6 → 1187,7 |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp; |
u32 pp_ctrl_reg; |
if (!is_edp(intel_dp)) |
return; |
1285,10 → 1195,13 |
intel_panel_disable_backlight(dev); |
DRM_DEBUG_KMS("\n"); |
pp = ironlake_get_pp_control(dev_priv); |
pp = ironlake_get_pp_control(intel_dp); |
pp &= ~EDP_BLC_ENABLE; |
I915_WRITE(PCH_PP_CONTROL, pp); |
POSTING_READ(PCH_PP_CONTROL); |
pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; |
I915_WRITE(pp_ctrl_reg, pp); |
POSTING_READ(pp_ctrl_reg); |
msleep(intel_dp->backlight_off_delay); |
} |
1384,7 → 1297,7 |
if (!(tmp & DP_PORT_EN)) |
return false; |
if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { |
if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { |
*pipe = PORT_TO_PIPE_CPT(tmp); |
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { |
*pipe = PORT_TO_PIPE(tmp); |
1441,9 → 1354,11 |
static void intel_post_disable_dp(struct intel_encoder *encoder) |
{ |
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
struct drm_device *dev = encoder->base.dev; |
if (is_cpu_edp(intel_dp)) { |
intel_dp_link_down(intel_dp); |
if (!IS_VALLEYVIEW(dev)) |
ironlake_edp_pll_off(intel_dp); |
} |
} |
1464,6 → 1379,7 |
ironlake_edp_panel_on(intel_dp); |
ironlake_edp_panel_vdd_off(intel_dp, true); |
intel_dp_complete_link_train(intel_dp); |
intel_dp_stop_link_train(intel_dp); |
ironlake_edp_backlight_on(intel_dp); |
} |
1470,8 → 1386,9 |
static void intel_pre_enable_dp(struct intel_encoder *encoder) |
{ |
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
struct drm_device *dev = encoder->base.dev; |
if (is_cpu_edp(intel_dp)) |
if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) |
ironlake_edp_pll_on(intel_dp); |
} |
1548,7 → 1465,7 |
{ |
struct drm_device *dev = intel_dp_to_dev(intel_dp); |
if (IS_HASWELL(dev)) { |
if (HAS_DDI(dev)) { |
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { |
case DP_TRAIN_VOLTAGE_SWING_400: |
return DP_TRAIN_PRE_EMPHASIS_9_5; |
1756,7 → 1673,7 |
uint32_t signal_levels, mask; |
uint8_t train_set = intel_dp->train_set[0]; |
if (IS_HASWELL(dev)) { |
if (HAS_DDI(dev)) { |
signal_levels = intel_hsw_signal_levels(train_set); |
mask = DDI_BUF_EMP_MASK; |
} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { |
1785,10 → 1702,9 |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum port port = intel_dig_port->port; |
int ret; |
uint32_t temp; |
if (IS_HASWELL(dev)) { |
temp = I915_READ(DP_TP_CTL(port)); |
if (HAS_DDI(dev)) { |
uint32_t temp = I915_READ(DP_TP_CTL(port)); |
if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) |
temp |= DP_TP_CTL_SCRAMBLE_DISABLE; |
1798,18 → 1714,6 |
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; |
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { |
case DP_TRAINING_PATTERN_DISABLE: |
if (port != PORT_A) { |
temp |= DP_TP_CTL_LINK_TRAIN_IDLE; |
I915_WRITE(DP_TP_CTL(port), temp); |
if (wait_for((I915_READ(DP_TP_STATUS(port)) & |
DP_TP_STATUS_IDLE_DONE), 1)) |
DRM_ERROR("Timed out waiting for DP idle patterns\n"); |
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; |
} |
temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; |
break; |
1885,6 → 1789,37 |
return true; |
} |
static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) |
{ |
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); |
struct drm_device *dev = intel_dig_port->base.base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum port port = intel_dig_port->port; |
uint32_t val; |
if (!HAS_DDI(dev)) |
return; |
val = I915_READ(DP_TP_CTL(port)); |
val &= ~DP_TP_CTL_LINK_TRAIN_MASK; |
val |= DP_TP_CTL_LINK_TRAIN_IDLE; |
I915_WRITE(DP_TP_CTL(port), val); |
/* |
* On PORT_A we can have only eDP in SST mode. There the only reason |
* we need to set idle transmission mode is to work around a HW issue |
* where we enable the pipe while not in idle link-training mode. |
* In this case there is requirement to wait for a minimum number of |
* idle patterns to be sent. |
*/ |
if (port == PORT_A) |
return; |
if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_IDLE_DONE), |
1)) |
DRM_ERROR("Timed out waiting for DP idle patterns\n"); |
} |
/* Enable corresponding port and start training pattern 1 */ |
void |
intel_dp_start_link_train(struct intel_dp *intel_dp) |
2027,12 → 1962,21 |
++tries; |
} |
intel_dp_set_idle_link_train(intel_dp); |
intel_dp->DP = DP; |
if (channel_eq) |
DRM_DEBUG_KMS("Channel EQ done. DP Training successfull\n"); |
DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n"); |
intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE); |
} |
void intel_dp_stop_link_train(struct intel_dp *intel_dp) |
{ |
intel_dp_set_link_train(intel_dp, intel_dp->DP, |
DP_TRAINING_PATTERN_DISABLE); |
} |
static void |
intel_dp_link_down(struct intel_dp *intel_dp) |
{ |
2238,6 → 2182,7 |
drm_get_encoder_name(&intel_encoder->base)); |
intel_dp_start_link_train(intel_dp); |
intel_dp_complete_link_train(intel_dp); |
intel_dp_stop_link_train(intel_dp); |
} |
} |
2311,6 → 2256,16 |
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); |
uint32_t bit; |
/* Can't disconnect eDP, but you can close the lid... */ |
if (is_edp(intel_dp)) { |
enum drm_connector_status status; |
status = intel_panel_detect(dev); |
if (status == connector_status_unknown) |
status = connector_status_connected; |
return status; |
} |
switch (intel_dig_port->port) { |
case PORT_B: |
bit = PORTB_HOTPLUG_LIVE_STATUS; |
2492,6 → 2447,9 |
} |
if (property == dev_priv->broadcast_rgb_property) { |
bool old_auto = intel_dp->color_range_auto; |
uint32_t old_range = intel_dp->color_range; |
switch (val) { |
case INTEL_BROADCAST_RGB_AUTO: |
intel_dp->color_range_auto = true; |
2507,6 → 2465,11 |
default: |
return -EINVAL; |
} |
if (old_auto == intel_dp->color_range_auto && |
old_range == intel_dp->color_range) |
return 0; |
goto done; |
} |
2538,7 → 2501,6 |
static void |
intel_dp_destroy(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
struct intel_dp *intel_dp = intel_attached_dp(connector); |
struct intel_connector *intel_connector = to_intel_connector(connector); |
2545,10 → 2507,8 |
if (!IS_ERR_OR_NULL(intel_connector->edid)) |
kfree(intel_connector->edid); |
if (is_edp(intel_dp)) { |
intel_panel_destroy_backlight(dev); |
if (is_edp(intel_dp)) |
intel_panel_fini(&intel_connector->panel); |
} |
drm_sysfs_connector_remove(connector); |
drm_connector_cleanup(connector); |
2573,7 → 2533,6 |
} |
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { |
.mode_fixup = intel_dp_mode_fixup, |
.mode_set = intel_dp_mode_set, |
}; |
2669,15 → 2628,28 |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct edp_power_seq cur, vbt, spec, final; |
u32 pp_on, pp_off, pp_div, pp; |
int pp_control_reg, pp_on_reg, pp_off_reg, pp_div_reg; |
if (HAS_PCH_SPLIT(dev)) { |
pp_control_reg = PCH_PP_CONTROL; |
pp_on_reg = PCH_PP_ON_DELAYS; |
pp_off_reg = PCH_PP_OFF_DELAYS; |
pp_div_reg = PCH_PP_DIVISOR; |
} else { |
pp_control_reg = PIPEA_PP_CONTROL; |
pp_on_reg = PIPEA_PP_ON_DELAYS; |
pp_off_reg = PIPEA_PP_OFF_DELAYS; |
pp_div_reg = PIPEA_PP_DIVISOR; |
} |
/* Workaround: Need to write PP_CONTROL with the unlock key as |
* the very first thing. */ |
pp = ironlake_get_pp_control(dev_priv); |
I915_WRITE(PCH_PP_CONTROL, pp); |
pp = ironlake_get_pp_control(intel_dp); |
I915_WRITE(pp_control_reg, pp); |
pp_on = I915_READ(PCH_PP_ON_DELAYS); |
pp_off = I915_READ(PCH_PP_OFF_DELAYS); |
pp_div = I915_READ(PCH_PP_DIVISOR); |
pp_on = I915_READ(pp_on_reg); |
pp_off = I915_READ(pp_off_reg); |
pp_div = I915_READ(pp_div_reg); |
/* Pull timing values out of registers */ |
cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> |
2752,8 → 2724,23 |
struct edp_power_seq *seq) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pp_on, pp_off, pp_div; |
u32 pp_on, pp_off, pp_div, port_sel = 0; |
int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); |
int pp_on_reg, pp_off_reg, pp_div_reg; |
if (HAS_PCH_SPLIT(dev)) { |
pp_on_reg = PCH_PP_ON_DELAYS; |
pp_off_reg = PCH_PP_OFF_DELAYS; |
pp_div_reg = PCH_PP_DIVISOR; |
} else { |
pp_on_reg = PIPEA_PP_ON_DELAYS; |
pp_off_reg = PIPEA_PP_OFF_DELAYS; |
pp_div_reg = PIPEA_PP_DIVISOR; |
} |
if (IS_VALLEYVIEW(dev)) |
port_sel = I915_READ(pp_on_reg) & 0xc0000000; |
/* And finally store the new values in the power sequencer. */ |
pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | |
(seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT); |
2761,8 → 2748,7 |
(seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); |
/* Compute the divisor for the pp clock, simply match the Bspec |
* formula. */ |
pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1) |
<< PP_REFERENCE_DIVIDER_SHIFT; |
pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; |
pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) |
<< PANEL_POWER_CYCLE_DELAY_SHIFT); |
2770,19 → 2756,21 |
* power sequencer any more. */ |
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { |
if (is_cpu_edp(intel_dp)) |
pp_on |= PANEL_POWER_PORT_DP_A; |
port_sel = PANEL_POWER_PORT_DP_A; |
else |
pp_on |= PANEL_POWER_PORT_DP_D; |
port_sel = PANEL_POWER_PORT_DP_D; |
} |
I915_WRITE(PCH_PP_ON_DELAYS, pp_on); |
I915_WRITE(PCH_PP_OFF_DELAYS, pp_off); |
I915_WRITE(PCH_PP_DIVISOR, pp_div); |
pp_on |= port_sel; |
I915_WRITE(pp_on_reg, pp_on); |
I915_WRITE(pp_off_reg, pp_off); |
I915_WRITE(pp_div_reg, pp_div); |
DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", |
I915_READ(PCH_PP_ON_DELAYS), |
I915_READ(PCH_PP_OFF_DELAYS), |
I915_READ(PCH_PP_DIVISOR)); |
I915_READ(pp_on_reg), |
I915_READ(pp_off_reg), |
I915_READ(pp_div_reg)); |
} |
void |
2829,7 → 2817,6 |
drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); |
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
connector->interlace_allowed = true; |
connector->doublescan_allowed = 0; |
2844,27 → 2831,46 |
else |
intel_connector->get_hw_state = intel_connector_get_hw_state; |
intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; |
if (HAS_DDI(dev)) { |
switch (intel_dig_port->port) { |
case PORT_A: |
intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; |
break; |
case PORT_B: |
intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; |
break; |
case PORT_C: |
intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; |
break; |
case PORT_D: |
intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; |
break; |
default: |
BUG(); |
} |
} |
/* Set up the DDC bus. */ |
switch (port) { |
case PORT_A: |
intel_encoder->hpd_pin = HPD_PORT_A; |
name = "DPDDC-A"; |
break; |
case PORT_B: |
dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; |
intel_encoder->hpd_pin = HPD_PORT_B; |
name = "DPDDC-B"; |
break; |
case PORT_C: |
dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; |
intel_encoder->hpd_pin = HPD_PORT_C; |
name = "DPDDC-C"; |
break; |
case PORT_D: |
dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; |
intel_encoder->hpd_pin = HPD_PORT_D; |
name = "DPDDC-D"; |
break; |
default: |
WARN(1, "Invalid port %c\n", port_name(port)); |
break; |
BUG(); |
} |
if (is_edp(intel_dp)) |
2974,6 → 2980,7 |
DRM_MODE_ENCODER_TMDS); |
drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); |
intel_encoder->compute_config = intel_dp_compute_config; |
intel_encoder->enable = intel_enable_dp; |
intel_encoder->pre_enable = intel_pre_enable_dp; |
intel_encoder->disable = intel_disable_dp; |
/drivers/video/drm/i915/intel_drv.h |
---|
35,13 → 35,23 |
#define KBUILD_MODNAME "i915.dll" |
#define cpu_relax() asm volatile("rep; nop") |
/** |
* _wait_for - magic (register) wait macro |
* |
* Does the right thing for modeset paths when run under kdgb or similar atomic |
* contexts. Note that it's important that we check the condition again after |
* having timed out, since the timeout could be due to preemption or similar and |
* we've never had a chance to check the condition before the timeout. |
*/ |
#define _wait_for(COND, MS, W) ({ \ |
unsigned long timeout__ = GetTimerTicks() + msecs_to_jiffies(MS); \ |
int ret__ = 0; \ |
while (!(COND)) { \ |
if (time_after(GetTimerTicks(), timeout__)) { \ |
if (!(COND)) \ |
ret__ = -ETIMEDOUT; \ |
break; \ |
} \ |
112,34 → 122,6 |
#define INTEL_DVO_CHIP_TMDS 2 |
#define INTEL_DVO_CHIP_TVOUT 4 |
/* drm_display_mode->private_flags */ |
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) |
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) |
#define INTEL_MODE_DP_FORCE_6BPC (0x10) |
/* This flag must be set by the encoder's mode_fixup if it changes the crtc |
* timings in the mode to prevent the crtc fixup from overwriting them. |
* Currently only lvds needs that. */ |
#define INTEL_MODE_CRTC_TIMINGS_SET (0x20) |
/* |
* Set when limited 16-235 (as opposed to full 0-255) RGB color range is |
* to be used. |
*/ |
#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40) |
static inline void |
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, |
int multiplier) |
{ |
mode->clock *= multiplier; |
mode->private_flags |= multiplier; |
} |
static inline int |
intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) |
{ |
return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; |
} |
struct intel_framebuffer { |
struct drm_framebuffer base; |
struct drm_i915_gem_object *obj; |
169,9 → 151,12 |
bool cloneable; |
bool connectors_active; |
void (*hot_plug)(struct intel_encoder *); |
bool (*compute_config)(struct intel_encoder *, |
struct intel_crtc_config *); |
void (*pre_pll_enable)(struct intel_encoder *); |
void (*pre_enable)(struct intel_encoder *); |
void (*enable)(struct intel_encoder *); |
void (*mode_set)(struct intel_encoder *intel_encoder); |
void (*disable)(struct intel_encoder *); |
void (*post_disable)(struct intel_encoder *); |
/* Read out the current hw state of this connector, returning true if |
179,6 → 164,7 |
* it is connected to in the pipe parameter. */ |
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); |
int crtc_mask; |
enum hpd_pin hpd_pin; |
}; |
struct intel_panel { |
208,13 → 194,65 |
/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ |
struct edid *edid; |
/* since POLL and HPD connectors may use the same HPD line keep the native |
state of connector->polled in case hotplug storm detection changes it */ |
u8 polled; |
}; |
struct intel_crtc_config { |
struct drm_display_mode requested_mode; |
struct drm_display_mode adjusted_mode; |
/* This flag must be set by the encoder's compute_config callback if it |
* changes the crtc timings in the mode to prevent the crtc fixup from |
* overwriting them. Currently only lvds needs that. */ |
bool timings_set; |
/* Whether to set up the PCH/FDI. Note that we never allow sharing |
* between pch encoders and cpu encoders. */ |
bool has_pch_encoder; |
/* CPU Transcoder for the pipe. Currently this can only differ from the |
* pipe on Haswell (where we have a special eDP transcoder). */ |
enum transcoder cpu_transcoder; |
/* |
* Use reduced/limited/broadcast rbg range, compressing from the full |
* range fed into the crtcs. |
*/ |
bool limited_color_range; |
/* DP has a bunch of special case unfortunately, so mark the pipe |
* accordingly. */ |
bool has_dp_encoder; |
bool dither; |
/* Controls for the clock computation, to override various stages. */ |
bool clock_set; |
/* Settings for the intel dpll used on pretty much everything but |
* haswell. */ |
struct dpll { |
unsigned n; |
unsigned m1, m2; |
unsigned p1, p2; |
} dpll; |
int pipe_bpp; |
struct intel_link_m_n dp_m_n; |
/** |
* This is currently used by DP and HDMI encoders since those can have a |
* target pixel clock != the port link clock (which is currently stored |
* in adjusted_mode->clock). |
*/ |
int pixel_target_clock; |
/* Used by SDVO (and if we ever fix it, HDMI). */ |
unsigned pixel_multiplier; |
}; |
struct intel_crtc { |
struct drm_crtc base; |
enum pipe pipe; |
enum plane plane; |
enum transcoder cpu_transcoder; |
u8 lut_r[256], lut_g[256], lut_b[256]; |
/* |
* Whether the crtc and the connected output pipeline is active. Implies |
241,8 → 279,9 |
int16_t cursor_x, cursor_y; |
int16_t cursor_width, cursor_height; |
bool cursor_visible; |
unsigned int bpp; |
struct intel_crtc_config config; |
/* We can share PLLs across outputs if the timings match */ |
struct intel_pch_pll *pch_pll; |
uint32_t ddi_pll_sel; |
253,11 → 292,16 |
struct intel_plane { |
struct drm_plane base; |
int plane; |
enum pipe pipe; |
struct drm_i915_gem_object *obj; |
bool can_scale; |
int max_downscale; |
u32 lut_r[1024], lut_g[1024], lut_b[1024]; |
int crtc_x, crtc_y; |
unsigned int crtc_w, crtc_h; |
uint32_t src_x, src_y; |
uint32_t src_w, src_h; |
void (*update_plane)(struct drm_plane *plane, |
struct drm_framebuffer *fb, |
struct drm_i915_gem_object *obj, |
358,7 → 402,7 |
} __attribute__((packed)); |
struct intel_hdmi { |
u32 sdvox_reg; |
u32 hdmi_reg; |
int ddc_bus; |
uint32_t color_range; |
bool color_range_auto; |
377,6 → 421,7 |
struct intel_dp { |
uint32_t output_reg; |
uint32_t aux_ch_ctl_reg; |
uint32_t DP; |
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; |
bool has_audio; |
454,13 → 499,12 |
extern void intel_crt_init(struct drm_device *dev); |
extern void intel_hdmi_init(struct drm_device *dev, |
int sdvox_reg, enum port port); |
int hdmi_reg, enum port port); |
extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, |
struct intel_connector *intel_connector); |
extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); |
extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode); |
extern bool intel_hdmi_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config); |
extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); |
extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, |
bool is_sdvob); |
475,18 → 519,15 |
enum port port); |
extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, |
struct intel_connector *intel_connector); |
void |
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode); |
extern void intel_dp_init_link_config(struct intel_dp *intel_dp); |
extern void intel_dp_start_link_train(struct intel_dp *intel_dp); |
extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); |
extern void intel_dp_stop_link_train(struct intel_dp *intel_dp); |
extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); |
extern void intel_dp_encoder_destroy(struct drm_encoder *encoder); |
extern void intel_dp_check_link_status(struct intel_dp *intel_dp); |
extern bool intel_dp_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode); |
extern bool intel_dp_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config); |
extern bool intel_dpd_is_edp(struct drm_device *dev); |
extern void ironlake_edp_backlight_on(struct intel_dp *intel_dp); |
extern void ironlake_edp_backlight_off(struct intel_dp *intel_dp); |
494,11 → 535,8 |
extern void ironlake_edp_panel_off(struct intel_dp *intel_dp); |
extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); |
extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); |
extern void intel_edp_link_config(struct intel_encoder *, int *, int *); |
extern int intel_edp_target_clock(struct intel_encoder *, |
struct drm_display_mode *mode); |
extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); |
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); |
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); |
extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, |
enum plane plane); |
542,6 → 580,7 |
extern void intel_connector_dpms(struct drm_connector *, int mode); |
extern bool intel_connector_get_hw_state(struct intel_connector *connector); |
extern void intel_modeset_check_state(struct drm_device *dev); |
extern void intel_plane_restore(struct drm_plane *plane); |
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) |
647,6 → 686,10 |
extern void intel_write_eld(struct drm_encoder *encoder, |
struct drm_display_mode *mode); |
extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); |
extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, |
struct intel_link_m_n *m_n); |
extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, |
struct intel_link_m_n *m_n); |
extern void intel_prepare_ddi(struct drm_device *dev); |
extern void hsw_fdi_link_train(struct drm_crtc *crtc); |
extern void intel_ddi_init(struct drm_device *dev, enum port port); |
681,6 → 724,7 |
extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); |
extern void intel_gpu_ips_teardown(void); |
extern bool intel_using_power_well(struct drm_device *dev); |
extern void intel_init_power_well(struct drm_device *dev); |
extern void intel_set_power_well(struct drm_device *dev, bool enable); |
extern void intel_enable_gt_powersave(struct drm_device *dev); |
692,7 → 736,7 |
enum pipe *pipe); |
extern int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv); |
extern void intel_ddi_pll_init(struct drm_device *dev); |
extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc); |
extern void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc); |
extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, |
enum transcoder cpu_transcoder); |
extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); |
706,4 → 750,6 |
intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); |
extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); |
extern void intel_display_handle_reset(struct drm_device *dev); |
#endif /* __INTEL_DRV_H__ */ |
/drivers/video/drm/i915/intel_dvo.c |
---|
448,6 → 448,7 |
const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; |
struct i2c_adapter *i2c; |
int gpio; |
bool dvoinit; |
/* Allow the I2C driver info to specify the GPIO to be used in |
* special cases, but otherwise default to what's defined |
467,7 → 468,17 |
i2c = intel_gmbus_get_adapter(dev_priv, gpio); |
intel_dvo->dev = *dvo; |
if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) |
/* GMBUS NAK handling seems to be unstable, hence let the |
* transmitter detection run in bit banging mode for now. |
*/ |
intel_gmbus_force_bit(i2c, true); |
dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c); |
intel_gmbus_force_bit(i2c, false); |
if (!dvoinit) |
continue; |
intel_encoder->type = INTEL_OUTPUT_DVO; |
/drivers/video/drm/i915/intel_fb.c |
---|
208,7 → 208,6 |
mutex_unlock(&dev->struct_mutex); |
// vga_switcheroo_client_fb_set(dev->pdev, info); |
fb_obj = obj; |
244,7 → 243,7 |
ifbdev->helper.funcs = &intel_fb_helper_funcs; |
ret = drm_fb_helper_init(dev, &ifbdev->helper, |
dev_priv->num_pipe, |
INTEL_INFO(dev)->num_pipes, |
INTELFB_CONN_LIMIT); |
if (ret) { |
kfree(ifbdev); |
/drivers/video/drm/i915/intel_hdmi.c |
---|
50,7 → 50,7 |
enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; |
WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, |
WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, |
"HDMI port enabled, expecting disabled\n"); |
} |
120,13 → 120,14 |
} |
} |
static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe) |
static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, |
enum transcoder cpu_transcoder) |
{ |
switch (frame->type) { |
case DIP_TYPE_AVI: |
return HSW_TVIDEO_DIP_AVI_DATA(pipe); |
return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); |
case DIP_TYPE_SPD: |
return HSW_TVIDEO_DIP_SPD_DATA(pipe); |
return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); |
default: |
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); |
return 0; |
293,8 → 294,8 |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe); |
u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); |
u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder); |
unsigned int i, len = DIP_HEADER_SIZE + frame->len; |
u32 val = I915_READ(ctl_reg); |
332,6 → 333,7 |
struct drm_display_mode *adjusted_mode) |
{ |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
struct dip_infoframe avi_if = { |
.type = DIP_TYPE_AVI, |
.ver = DIP_VERSION_AVI, |
342,7 → 344,7 |
avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; |
if (intel_hdmi->rgb_quant_range_selectable) { |
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) |
if (intel_crtc->config.limited_color_range) |
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; |
else |
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; |
568,7 → 570,7 |
struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); |
u32 val = I915_READ(reg); |
assert_hdmi_port_disabled(intel_hdmi); |
597,40 → 599,40 |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
u32 sdvox; |
u32 hdmi_val; |
sdvox = SDVO_ENCODING_HDMI; |
if (!HAS_PCH_SPLIT(dev)) |
sdvox |= intel_hdmi->color_range; |
hdmi_val = SDVO_ENCODING_HDMI; |
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) |
hdmi_val |= intel_hdmi->color_range; |
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) |
sdvox |= SDVO_VSYNC_ACTIVE_HIGH; |
hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; |
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
sdvox |= SDVO_HSYNC_ACTIVE_HIGH; |
hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; |
if (intel_crtc->bpp > 24) |
sdvox |= COLOR_FORMAT_12bpc; |
if (intel_crtc->config.pipe_bpp > 24) |
hdmi_val |= HDMI_COLOR_FORMAT_12bpc; |
else |
sdvox |= COLOR_FORMAT_8bpc; |
hdmi_val |= SDVO_COLOR_FORMAT_8bpc; |
/* Required on CPT */ |
if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) |
sdvox |= HDMI_MODE_SELECT; |
hdmi_val |= HDMI_MODE_SELECT_HDMI; |
if (intel_hdmi->has_audio) { |
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", |
pipe_name(intel_crtc->pipe)); |
sdvox |= SDVO_AUDIO_ENABLE; |
sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; |
hdmi_val |= SDVO_AUDIO_ENABLE; |
hdmi_val |= HDMI_MODE_SELECT_HDMI; |
intel_write_eld(encoder, adjusted_mode); |
} |
if (HAS_PCH_CPT(dev)) |
sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); |
else if (intel_crtc->pipe == PIPE_B) |
sdvox |= SDVO_PIPE_B_SELECT; |
hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); |
else |
hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe); |
I915_WRITE(intel_hdmi->sdvox_reg, sdvox); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); |
POSTING_READ(intel_hdmi->hdmi_reg); |
intel_hdmi->set_infoframes(encoder, adjusted_mode); |
} |
643,7 → 645,7 |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
u32 tmp; |
tmp = I915_READ(intel_hdmi->sdvox_reg); |
tmp = I915_READ(intel_hdmi->hdmi_reg); |
if (!(tmp & SDVO_ENABLE)) |
return false; |
660,6 → 662,7 |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
u32 temp; |
u32 enable_bits = SDVO_ENABLE; |
667,38 → 670,32 |
if (intel_hdmi->has_audio) |
enable_bits |= SDVO_AUDIO_ENABLE; |
temp = I915_READ(intel_hdmi->sdvox_reg); |
temp = I915_READ(intel_hdmi->hdmi_reg); |
/* HW workaround for IBX, we need to move the port to transcoder A |
* before disabling it. */ |
if (HAS_PCH_IBX(dev)) { |
struct drm_crtc *crtc = encoder->base.crtc; |
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; |
* before disabling it, so restore the transcoder select bit here. */ |
if (HAS_PCH_IBX(dev)) |
enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); |
/* Restore the transcoder select bit. */ |
if (pipe == PIPE_B) |
enable_bits |= SDVO_PIPE_B_SELECT; |
} |
/* HW workaround, need to toggle enable bit off and on for 12bpc, but |
* we do this anyway which shows more stable in testing. |
*/ |
if (HAS_PCH_SPLIT(dev)) { |
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); |
POSTING_READ(intel_hdmi->hdmi_reg); |
} |
temp |= enable_bits; |
I915_WRITE(intel_hdmi->sdvox_reg, temp); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
/* HW workaround, need to write this twice for issue that may result |
* in first write getting masked. |
*/ |
if (HAS_PCH_SPLIT(dev)) { |
I915_WRITE(intel_hdmi->sdvox_reg, temp); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
} |
} |
710,7 → 707,7 |
u32 temp; |
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; |
temp = I915_READ(intel_hdmi->sdvox_reg); |
temp = I915_READ(intel_hdmi->hdmi_reg); |
/* HW workaround for IBX, we need to move the port to transcoder A |
* before disabling it. */ |
720,12 → 717,12 |
if (temp & SDVO_PIPE_B_SELECT) { |
temp &= ~SDVO_PIPE_B_SELECT; |
I915_WRITE(intel_hdmi->sdvox_reg, temp); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
/* Again we need to write this twice. */ |
I915_WRITE(intel_hdmi->sdvox_reg, temp); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
/* Transcoder selection bits only update |
* effectively on vblank. */ |
740,21 → 737,21 |
* we do this anyway which shows more stable in testing. |
*/ |
if (HAS_PCH_SPLIT(dev)) { |
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); |
POSTING_READ(intel_hdmi->hdmi_reg); |
} |
temp &= ~enable_bits; |
I915_WRITE(intel_hdmi->sdvox_reg, temp); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
/* HW workaround, need to write this twice for issue that may result |
* in first write getting masked. |
*/ |
if (HAS_PCH_SPLIT(dev)) { |
I915_WRITE(intel_hdmi->sdvox_reg, temp); |
POSTING_READ(intel_hdmi->sdvox_reg); |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
} |
} |
772,24 → 769,41 |
return MODE_OK; |
} |
bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
bool intel_hdmi_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
struct drm_device *dev = encoder->base.dev; |
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
if (intel_hdmi->color_range_auto) { |
/* See CEA-861-E - 5.1 Default Encoding Parameters */ |
if (intel_hdmi->has_hdmi_sink && |
drm_match_cea_mode(adjusted_mode) > 1) |
intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; |
intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; |
else |
intel_hdmi->color_range = 0; |
} |
if (intel_hdmi->color_range) |
adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; |
pipe_config->limited_color_range = true; |
if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) |
pipe_config->has_pch_encoder = true; |
/* |
* HDMI is either 12 or 8, so if the display lets 10bpc sneak |
* through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi |
* outputs. |
*/ |
if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) { |
DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); |
pipe_config->pipe_bpp = 12*3; |
} else { |
DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); |
pipe_config->pipe_bpp = 8*3; |
} |
return true; |
} |
906,6 → 920,9 |
} |
if (property == dev_priv->broadcast_rgb_property) { |
bool old_auto = intel_hdmi->color_range_auto; |
uint32_t old_range = intel_hdmi->color_range; |
switch (val) { |
case INTEL_BROADCAST_RGB_AUTO: |
intel_hdmi->color_range_auto = true; |
916,11 → 933,16 |
break; |
case INTEL_BROADCAST_RGB_LIMITED: |
intel_hdmi->color_range_auto = false; |
intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; |
intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; |
break; |
default: |
return -EINVAL; |
} |
if (old_auto == intel_hdmi->color_range_auto && |
old_range == intel_hdmi->color_range) |
return 0; |
goto done; |
} |
941,7 → 963,6 |
} |
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { |
.mode_fixup = intel_hdmi_mode_fixup, |
.mode_set = intel_hdmi_mode_set, |
}; |
985,7 → 1006,6 |
DRM_MODE_CONNECTOR_HDMIA); |
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
connector->interlace_allowed = 1; |
connector->doublescan_allowed = 0; |
992,29 → 1012,30 |
switch (port) { |
case PORT_B: |
intel_hdmi->ddc_bus = GMBUS_PORT_DPB; |
dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; |
intel_encoder->hpd_pin = HPD_PORT_B; |
break; |
case PORT_C: |
intel_hdmi->ddc_bus = GMBUS_PORT_DPC; |
dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; |
intel_encoder->hpd_pin = HPD_PORT_C; |
break; |
case PORT_D: |
intel_hdmi->ddc_bus = GMBUS_PORT_DPD; |
dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; |
intel_encoder->hpd_pin = HPD_PORT_D; |
break; |
case PORT_A: |
intel_encoder->hpd_pin = HPD_PORT_A; |
/* Internal port only for eDP. */ |
default: |
BUG(); |
} |
if (!HAS_PCH_SPLIT(dev)) { |
if (IS_VALLEYVIEW(dev)) { |
intel_hdmi->write_infoframe = vlv_write_infoframe; |
intel_hdmi->set_infoframes = vlv_set_infoframes; |
} else if (!HAS_PCH_SPLIT(dev)) { |
intel_hdmi->write_infoframe = g4x_write_infoframe; |
intel_hdmi->set_infoframes = g4x_set_infoframes; |
} else if (IS_VALLEYVIEW(dev)) { |
intel_hdmi->write_infoframe = vlv_write_infoframe; |
intel_hdmi->set_infoframes = vlv_set_infoframes; |
} else if (IS_HASWELL(dev)) { |
} else if (HAS_DDI(dev)) { |
intel_hdmi->write_infoframe = hsw_write_infoframe; |
intel_hdmi->set_infoframes = hsw_set_infoframes; |
} else if (HAS_PCH_IBX(dev)) { |
1045,7 → 1066,7 |
} |
} |
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) |
void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) |
{ |
struct intel_digital_port *intel_dig_port; |
struct intel_encoder *intel_encoder; |
1069,6 → 1090,7 |
DRM_MODE_ENCODER_TMDS); |
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); |
intel_encoder->compute_config = intel_hdmi_compute_config; |
intel_encoder->enable = intel_enable_hdmi; |
intel_encoder->disable = intel_disable_hdmi; |
intel_encoder->get_hw_state = intel_hdmi_get_hw_state; |
1078,7 → 1100,7 |
intel_encoder->cloneable = false; |
intel_dig_port->port = port; |
intel_dig_port->hdmi.sdvox_reg = sdvox_reg; |
intel_dig_port->hdmi.hdmi_reg = hdmi_reg; |
intel_dig_port->dp.output_reg = 0; |
intel_hdmi_init_connector(intel_dig_port, intel_connector); |
/drivers/video/drm/i915/intel_i2c.c |
---|
228,7 → 228,7 |
* need to wake up periodically and check that ourselves. */ |
I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en); |
for (i = 0; i < msecs_to_jiffies(50) + 1; i++) { |
for (i = 0; i < msecs_to_jiffies_timeout(50); i++) { |
prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait, |
TASK_UNINTERRUPTIBLE); |
263,7 → 263,8 |
/* Important: The hw handles only the first bit, so set only one! */ |
I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN); |
ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10); |
ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, |
msecs_to_jiffies_timeout(10)); |
I915_WRITE(GMBUS4 + reg_offset, 0); |
522,7 → 523,9 |
struct drm_i915_private *dev_priv = dev->dev_private; |
int ret, i; |
if (HAS_PCH_SPLIT(dev)) |
if (HAS_PCH_NOP(dev)) |
return 0; |
else if (HAS_PCH_SPLIT(dev)) |
dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; |
else if (IS_VALLEYVIEW(dev)) |
dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; |
/drivers/video/drm/i915/intel_lvds.c |
---|
261,8 → 261,6 |
mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; |
mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; |
mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; |
} |
static void |
284,8 → 282,6 |
mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; |
mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; |
mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; |
} |
static inline u32 panel_fitter_scaling(u32 source, u32 target) |
301,17 → 297,20 |
return (FACTOR * ratio + FACTOR/2) / FACTOR; |
} |
static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_device *dev = intel_encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); |
struct intel_lvds_encoder *lvds_encoder = |
to_lvds_encoder(&intel_encoder->base); |
struct intel_connector *intel_connector = |
&lvds_encoder->attached_connector->base; |
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
struct drm_display_mode *mode = &pipe_config->requested_mode; |
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; |
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
unsigned int lvds_bpp; |
int pipe; |
/* Should never happen!! */ |
323,6 → 322,17 |
if (intel_encoder_check_is_cloned(&lvds_encoder->base)) |
return false; |
if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) == |
LVDS_A3_POWER_UP) |
lvds_bpp = 8*3; |
else |
lvds_bpp = 6*3; |
if (lvds_bpp != pipe_config->pipe_bpp) { |
DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", |
pipe_config->pipe_bpp, lvds_bpp); |
pipe_config->pipe_bpp = lvds_bpp; |
} |
/* |
* We have timings from the BIOS for the panel, put them in |
* to the adjusted mode. The CRTC will be set up for this mode, |
333,6 → 343,8 |
adjusted_mode); |
if (HAS_PCH_SPLIT(dev)) { |
pipe_config->has_pch_encoder = true; |
intel_pch_panel_fitting(dev, |
intel_connector->panel.fitting_mode, |
mode, adjusted_mode); |
359,6 → 371,7 |
I915_WRITE(BCLRPAT(pipe), 0); |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
pipe_config->timings_set = true; |
switch (intel_connector->panel.fitting_mode) { |
case DRM_MODE_SCALE_CENTER: |
618,7 → 631,6 |
if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) |
kfree(lvds_connector->base.edid); |
intel_panel_destroy_backlight(connector->dev); |
intel_panel_fini(&lvds_connector->base.panel); |
drm_sysfs_connector_remove(connector); |
661,7 → 673,6 |
} |
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { |
.mode_fixup = intel_lvds_mode_fixup, |
.mode_set = intel_lvds_mode_set, |
}; |
804,10 → 815,10 |
}, |
{ |
.callback = intel_no_lvds_dmi_callback, |
.ident = "Hewlett-Packard HP t5740e Thin Client", |
.ident = "Hewlett-Packard HP t5740", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), |
DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"), |
DMI_MATCH(DMI_PRODUCT_NAME, " t5740"), |
}, |
}, |
{ |
850,6 → 861,14 |
DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"), |
}, |
}, |
{ |
.callback = intel_no_lvds_dmi_callback, |
.ident = "Fujitsu Esprimo Q900", |
.matches = { |
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"), |
}, |
}, |
{ } /* terminating entry */ |
}; |
1006,12 → 1025,15 |
{ |
/* With the introduction of the PCH we gained a dedicated |
* LVDS presence pin, use it. */ |
if (HAS_PCH_SPLIT(dev)) |
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) |
return true; |
/* Otherwise LVDS was only attached to mobile products, |
* except for the inglorious 830gm */ |
return IS_MOBILE(dev) && !IS_I830(dev); |
if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) |
return true; |
return false; |
} |
/** |
1089,6 → 1111,7 |
intel_encoder->enable = intel_enable_lvds; |
intel_encoder->pre_enable = intel_pre_enable_lvds; |
intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; |
intel_encoder->compute_config = intel_lvds_compute_config; |
intel_encoder->disable = intel_disable_lvds; |
intel_encoder->get_hw_state = intel_lvds_get_hw_state; |
intel_connector->get_hw_state = intel_connector_get_hw_state; |
/drivers/video/drm/i915/intel_panel.c |
---|
286,9 → 286,12 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
dev_priv->backlight_level = level; |
if (dev_priv->backlight_enabled) |
intel_panel_actually_set_backlight(dev, level); |
dev_priv->backlight.level = level; |
// if (dev_priv->backlight.device) |
// dev_priv->backlight.device->props.brightness = level; |
// if (dev_priv->backlight.enabled) |
// intel_panel_actually_set_backlight(dev, level); |
} |
void intel_panel_disable_backlight(struct drm_device *dev) |
295,7 → 298,7 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
dev_priv->backlight_enabled = false; |
dev_priv->backlight.enabled = false; |
intel_panel_actually_set_backlight(dev, 0); |
if (INTEL_INFO(dev)->gen >= 4) { |
318,8 → 321,12 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
if (dev_priv->backlight_level == 0) |
dev_priv->backlight_level = intel_panel_get_max_backlight(dev); |
if (dev_priv->backlight.level == 0) { |
dev_priv->backlight.level = intel_panel_get_max_backlight(dev); |
// if (dev_priv->backlight.device) |
// dev_priv->backlight.device->props.brightness = |
// dev_priv->backlight.level; |
} |
if (INTEL_INFO(dev)->gen >= 4) { |
uint32_t reg, tmp; |
335,7 → 342,7 |
if (tmp & BLM_PWM_ENABLE) |
goto set_level; |
if (dev_priv->num_pipe == 3) |
if (INTEL_INFO(dev)->num_pipes == 3) |
tmp &= ~BLM_PIPE_SELECT_IVB; |
else |
tmp &= ~BLM_PIPE_SELECT; |
360,8 → 367,8 |
* BLC_PWM_CPU_CTL may be cleared to zero automatically when these |
* registers are set. |
*/ |
dev_priv->backlight_enabled = true; |
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); |
dev_priv->backlight.enabled = true; |
intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); |
} |
static void intel_panel_init_backlight(struct drm_device *dev) |
368,8 → 375,8 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
dev_priv->backlight_level = intel_panel_get_backlight(dev); |
dev_priv->backlight_enabled = dev_priv->backlight_level != 0; |
dev_priv->backlight.level = intel_panel_get_backlight(dev); |
dev_priv->backlight.enabled = dev_priv->backlight.level != 0; |
} |
enum drm_connector_status |
405,8 → 412,7 |
static int intel_panel_get_brightness(struct backlight_device *bd) |
{ |
struct drm_device *dev = bl_get_data(bd); |
struct drm_i915_private *dev_priv = dev->dev_private; |
return dev_priv->backlight_level; |
return intel_panel_get_backlight(dev); |
} |
static const struct backlight_ops intel_panel_bl_ops = { |
422,25 → 428,28 |
intel_panel_init_backlight(dev); |
if (WARN_ON(dev_priv->backlight.device)) |
return -ENODEV; |
memset(&props, 0, sizeof(props)); |
props.type = BACKLIGHT_RAW; |
props.brightness = dev_priv->backlight.level; |
props.max_brightness = _intel_panel_get_max_backlight(dev); |
if (props.max_brightness == 0) { |
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); |
return -ENODEV; |
} |
dev_priv->backlight = |
dev_priv->backlight.device = |
backlight_device_register("intel_backlight", |
&connector->kdev, dev, |
&intel_panel_bl_ops, &props); |
if (IS_ERR(dev_priv->backlight)) { |
if (IS_ERR(dev_priv->backlight.device)) { |
DRM_ERROR("Failed to register backlight: %ld\n", |
PTR_ERR(dev_priv->backlight)); |
dev_priv->backlight = NULL; |
PTR_ERR(dev_priv->backlight.device)); |
dev_priv->backlight.device = NULL; |
return -ENODEV; |
} |
dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev); |
return 0; |
} |
447,9 → 456,11 |
void intel_panel_destroy_backlight(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
if (dev_priv->backlight) |
backlight_device_unregister(dev_priv->backlight); |
if (dev_priv->backlight.device) { |
backlight_device_unregister(dev_priv->backlight.device); |
dev_priv->backlight.device = NULL; |
} |
} |
#else |
int intel_panel_setup_backlight(struct drm_connector *connector) |
{ |
/drivers/video/drm/i915/intel_pm.c |
---|
25,9 → 25,6 |
* |
*/ |
#define iowrite32(v, addr) writel((v), (addr)) |
#define ioread32(addr) readl(addr) |
//#include <linux/cpufreq.h> |
#include "i915_drv.h" |
#include "intel_drv.h" |
1325,17 → 1322,17 |
vlv_update_drain_latency(dev); |
if (g4x_compute_wm0(dev, 0, |
if (g4x_compute_wm0(dev, PIPE_A, |
&valleyview_wm_info, latency_ns, |
&valleyview_cursor_wm_info, latency_ns, |
&planea_wm, &cursora_wm)) |
enabled |= 1; |
enabled |= 1 << PIPE_A; |
if (g4x_compute_wm0(dev, 1, |
if (g4x_compute_wm0(dev, PIPE_B, |
&valleyview_wm_info, latency_ns, |
&valleyview_cursor_wm_info, latency_ns, |
&planeb_wm, &cursorb_wm)) |
enabled |= 2; |
enabled |= 1 << PIPE_B; |
if (single_plane_enabled(enabled) && |
g4x_compute_srwm(dev, ffs(enabled) - 1, |
1381,17 → 1378,17 |
int plane_sr, cursor_sr; |
unsigned int enabled = 0; |
if (g4x_compute_wm0(dev, 0, |
if (g4x_compute_wm0(dev, PIPE_A, |
&g4x_wm_info, latency_ns, |
&g4x_cursor_wm_info, latency_ns, |
&planea_wm, &cursora_wm)) |
enabled |= 1; |
enabled |= 1 << PIPE_A; |
if (g4x_compute_wm0(dev, 1, |
if (g4x_compute_wm0(dev, PIPE_B, |
&g4x_wm_info, latency_ns, |
&g4x_cursor_wm_info, latency_ns, |
&planeb_wm, &cursorb_wm)) |
enabled |= 2; |
enabled |= 1 << PIPE_B; |
if (single_plane_enabled(enabled) && |
g4x_compute_srwm(dev, ffs(enabled) - 1, |
1740,7 → 1737,7 |
unsigned int enabled; |
enabled = 0; |
if (g4x_compute_wm0(dev, 0, |
if (g4x_compute_wm0(dev, PIPE_A, |
&ironlake_display_wm_info, |
ILK_LP0_PLANE_LATENCY, |
&ironlake_cursor_wm_info, |
1751,10 → 1748,10 |
DRM_DEBUG_KMS("FIFO watermarks For pipe A -" |
" plane %d, " "cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 1; |
enabled |= 1 << PIPE_A; |
} |
if (g4x_compute_wm0(dev, 1, |
if (g4x_compute_wm0(dev, PIPE_B, |
&ironlake_display_wm_info, |
ILK_LP0_PLANE_LATENCY, |
&ironlake_cursor_wm_info, |
1765,7 → 1762,7 |
DRM_DEBUG_KMS("FIFO watermarks For pipe B -" |
" plane %d, cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 2; |
enabled |= 1 << PIPE_B; |
} |
/* |
1825,7 → 1822,7 |
unsigned int enabled; |
enabled = 0; |
if (g4x_compute_wm0(dev, 0, |
if (g4x_compute_wm0(dev, PIPE_A, |
&sandybridge_display_wm_info, latency, |
&sandybridge_cursor_wm_info, latency, |
&plane_wm, &cursor_wm)) { |
1836,10 → 1833,10 |
DRM_DEBUG_KMS("FIFO watermarks For pipe A -" |
" plane %d, " "cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 1; |
enabled |= 1 << PIPE_A; |
} |
if (g4x_compute_wm0(dev, 1, |
if (g4x_compute_wm0(dev, PIPE_B, |
&sandybridge_display_wm_info, latency, |
&sandybridge_cursor_wm_info, latency, |
&plane_wm, &cursor_wm)) { |
1850,7 → 1847,7 |
DRM_DEBUG_KMS("FIFO watermarks For pipe B -" |
" plane %d, cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 2; |
enabled |= 1 << PIPE_B; |
} |
/* |
1928,7 → 1925,7 |
unsigned int enabled; |
enabled = 0; |
if (g4x_compute_wm0(dev, 0, |
if (g4x_compute_wm0(dev, PIPE_A, |
&sandybridge_display_wm_info, latency, |
&sandybridge_cursor_wm_info, latency, |
&plane_wm, &cursor_wm)) { |
1939,10 → 1936,10 |
DRM_DEBUG_KMS("FIFO watermarks For pipe A -" |
" plane %d, " "cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 1; |
enabled |= 1 << PIPE_A; |
} |
if (g4x_compute_wm0(dev, 1, |
if (g4x_compute_wm0(dev, PIPE_B, |
&sandybridge_display_wm_info, latency, |
&sandybridge_cursor_wm_info, latency, |
&plane_wm, &cursor_wm)) { |
1953,10 → 1950,10 |
DRM_DEBUG_KMS("FIFO watermarks For pipe B -" |
" plane %d, cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 2; |
enabled |= 1 << PIPE_B; |
} |
if (g4x_compute_wm0(dev, 2, |
if (g4x_compute_wm0(dev, PIPE_C, |
&sandybridge_display_wm_info, latency, |
&sandybridge_cursor_wm_info, latency, |
&plane_wm, &cursor_wm)) { |
1967,7 → 1964,7 |
DRM_DEBUG_KMS("FIFO watermarks For pipe C -" |
" plane %d, cursor: %d\n", |
plane_wm, cursor_wm); |
enabled |= 3; |
enabled |= 1 << PIPE_C; |
} |
/* |
2484,7 → 2481,11 |
if (val == dev_priv->rps.cur_delay) |
return; |
if (IS_HASWELL(dev)) |
I915_WRITE(GEN6_RPNSWREQ, |
HSW_FREQUENCY(val)); |
else |
I915_WRITE(GEN6_RPNSWREQ, |
GEN6_FREQUENCY(val) | |
GEN6_OFFSET(0) | |
GEN6_AGGRESSIVE_TURBO); |
2578,8 → 2579,8 |
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); |
gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); |
/* In units of 100MHz */ |
dev_priv->rps.max_delay = rp_state_cap & 0xff; |
/* In units of 50MHz */ |
dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff; |
dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16; |
dev_priv->rps.cur_delay = 0; |
2625,12 → 2626,19 |
GEN6_RC_CTL_EI_MODE(1) | |
GEN6_RC_CTL_HW_ENABLE); |
if (IS_HASWELL(dev)) { |
I915_WRITE(GEN6_RPNSWREQ, |
HSW_FREQUENCY(10)); |
I915_WRITE(GEN6_RC_VIDEO_FREQ, |
HSW_FREQUENCY(12)); |
} else { |
I915_WRITE(GEN6_RPNSWREQ, |
GEN6_FREQUENCY(10) | |
GEN6_OFFSET(0) | |
GEN6_AGGRESSIVE_TURBO); |
I915_WRITE(GEN6_RC_VIDEO_FREQ, |
GEN6_FREQUENCY(12)); |
} |
I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); |
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, |
2655,9 → 2663,11 |
if (!ret) { |
pcu_mbox = 0; |
ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox); |
if (ret && pcu_mbox & (1<<31)) { /* OC supported */ |
dev_priv->rps.max_delay = pcu_mbox & 0xff; |
DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); |
if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */ |
DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n", |
(dev_priv->rps.max_delay & 0xff) * 50, |
(pcu_mbox & 0xff) * 50); |
dev_priv->rps.hw_max = pcu_mbox & 0xff; |
} |
} else { |
DRM_DEBUG_DRIVER("Failed to set the min frequency\n"); |
2695,8 → 2705,8 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int min_freq = 15; |
int gpu_freq; |
unsigned int ia_freq, max_ia_freq; |
unsigned int gpu_freq; |
unsigned int max_ia_freq, min_ring_freq; |
int scaling_factor = 180; |
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); |
2712,6 → 2722,10 |
/* Convert from kHz to MHz */ |
max_ia_freq /= 1000; |
min_ring_freq = I915_READ(MCHBAR_MIRROR_BASE_SNB + DCLK); |
/* convert DDR frequency from units of 133.3MHz to bandwidth */ |
min_ring_freq = (2 * 4 * min_ring_freq + 2) / 3; |
/* |
* For each potential GPU frequency, load a ring frequency we'd like |
* to use for memory access. We do this by specifying the IA frequency |
2720,10 → 2734,19 |
for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay; |
gpu_freq--) { |
int diff = dev_priv->rps.max_delay - gpu_freq; |
unsigned int ia_freq = 0, ring_freq = 0; |
/* |
* For GPU frequencies less than 750MHz, just use the lowest |
* ring freq. |
if (IS_HASWELL(dev)) { |
ring_freq = (gpu_freq * 5 + 3) / 4; |
ring_freq = max(min_ring_freq, ring_freq); |
/* leave ia_freq as the default, chosen by cpufreq */ |
} else { |
/* On older processors, there is no separate ring |
* clock domain, so in order to boost the bandwidth |
* of the ring, we need to upclock the CPU (ia_freq). |
* |
* For GPU frequencies less than 750MHz, |
* just use the lowest ring freq. |
*/ |
if (gpu_freq < min_freq) |
ia_freq = 800; |
2730,11 → 2753,13 |
else |
ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); |
ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); |
ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT; |
} |
sandybridge_pcode_write(dev_priv, |
GEN6_PCODE_WRITE_MIN_FREQ_TABLE, |
ia_freq | gpu_freq); |
ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT | |
ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT | |
gpu_freq); |
} |
} |
2845,7 → 2870,7 |
ret = intel_ring_idle(ring); |
dev_priv->mm.interruptible = was_interruptible; |
if (ret) { |
DRM_ERROR("failed to enable ironlake power power savings\n"); |
DRM_ERROR("failed to enable ironlake power savings\n"); |
ironlake_teardown_rc6(dev); |
return; |
} |
3590,6 → 3615,7 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
uint32_t val; |
/* |
* On Ibex Peak and Cougar Point, we need to disable clock |
3602,8 → 3628,17 |
/* The below fixes the weird display corruption, a few pixels shifted |
* downward, on (only) LVDS of some HP laptops with IVY. |
*/ |
for_each_pipe(pipe) |
I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_CHICKEN2_TIMING_OVERRIDE); |
for_each_pipe(pipe) { |
val = I915_READ(TRANS_CHICKEN2(pipe)); |
val |= TRANS_CHICKEN2_TIMING_OVERRIDE; |
val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; |
if (dev_priv->fdi_rx_polarity_inverted) |
val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; |
val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; |
val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; |
val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH; |
I915_WRITE(TRANS_CHICKEN2(pipe), val); |
} |
/* WADP0ClockGatingDisable */ |
for_each_pipe(pipe) { |
I915_WRITE(TRANS_CHICKEN1(pipe), |
3796,6 → 3831,9 |
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | |
GEN6_MBCTL_ENABLE_BOOT_FETCH); |
/* WaSwitchSolVfFArbitrationPriority */ |
I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); |
/* XXX: This is a workaround for early silicon revisions and should be |
* removed later. |
*/ |
3902,6 → 3940,7 |
snpcr |= GEN6_MBC_SNPCR_MED; |
I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); |
if (!HAS_PCH_NOP(dev)) |
cpt_init_clock_gating(dev); |
gen6_check_mch_setup(dev); |
3927,8 → 3966,10 |
CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | |
CHICKEN3_DGMG_DONE_FIX_DISABLE); |
/* WaDisablePSDDualDispatchEnable */ |
I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, |
_MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); |
_MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | |
GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); |
/* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ |
I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, |
3996,24 → 4037,20 |
_MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); |
/* |
* On ValleyView, the GUnit needs to signal the GT |
* when flip and other events complete. So enable |
* all the GUnit->GT interrupts here |
*/ |
I915_WRITE(VLV_DPFLIPSTAT, PIPEB_LINE_COMPARE_INT_EN | |
PIPEB_HLINE_INT_EN | PIPEB_VBLANK_INT_EN | |
SPRITED_FLIPDONE_INT_EN | SPRITEC_FLIPDONE_INT_EN | |
PLANEB_FLIPDONE_INT_EN | PIPEA_LINE_COMPARE_INT_EN | |
PIPEA_HLINE_INT_EN | PIPEA_VBLANK_INT_EN | |
SPRITEB_FLIPDONE_INT_EN | SPRITEA_FLIPDONE_INT_EN | |
PLANEA_FLIPDONE_INT_EN); |
/* |
* WaDisableVLVClockGating_VBIIssue |
* Disable clock gating on th GCFG unit to prevent a delay |
* in the reporting of vblank events. |
*/ |
I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS); |
I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff); |
/* Conservative clock gating settings for now */ |
I915_WRITE(0x9400, 0xffffffff); |
I915_WRITE(0x9404, 0xffffffff); |
I915_WRITE(0x9408, 0xffffffff); |
I915_WRITE(0x940c, 0xffffffff); |
I915_WRITE(0x9410, 0xffffffff); |
I915_WRITE(0x9414, 0xffffffff); |
I915_WRITE(0x9418, 0xffffffff); |
} |
static void g4x_init_clock_gating(struct drm_device *dev) |
4098,6 → 4135,22 |
dev_priv->display.init_clock_gating(dev); |
} |
/** |
* We should only use the power well if we explicitly asked the hardware to |
* enable it, so check if it's enabled and also check if we've requested it to |
* be enabled. |
*/ |
bool intel_using_power_well(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
if (IS_HASWELL(dev)) |
return I915_READ(HSW_PWR_WELL_DRIVER) == |
(HSW_PWR_WELL_ENABLE | HSW_PWR_WELL_STATE); |
else |
return true; |
} |
void intel_set_power_well(struct drm_device *dev, bool enable) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
4104,7 → 4157,7 |
bool is_enabled, enable_requested; |
uint32_t tmp; |
if (!IS_HASWELL(dev)) |
if (!HAS_POWER_WELL(dev)) |
return; |
if (!i915_disable_power_well && !enable) |
4142,7 → 4195,7 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
if (!IS_HASWELL(dev)) |
if (!HAS_POWER_WELL(dev)) |
return; |
/* For now, we need the power well to be always enabled. */ |
4204,7 → 4257,6 |
} |
dev_priv->display.init_clock_gating = gen6_init_clock_gating; |
} else if (IS_IVYBRIDGE(dev)) { |
/* FIXME: detect B0+ stepping and use auto training */ |
if (SNB_READ_WM0_LATENCY()) { |
dev_priv->display.update_wm = ivybridge_update_wm; |
dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; |
4302,21 → 4354,14 |
static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) |
{ |
u32 forcewake_ack; |
if (IS_HASWELL(dev_priv->dev)) |
forcewake_ack = FORCEWAKE_ACK_HSW; |
else |
forcewake_ack = FORCEWAKE_ACK; |
if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0, |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); |
I915_WRITE_NOTRACE(FORCEWAKE, FORCEWAKE_KERNEL); |
I915_WRITE_NOTRACE(FORCEWAKE, 1); |
POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ |
if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1), |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); |
4339,7 → 4384,7 |
else |
forcewake_ack = FORCEWAKE_MT_ACK; |
if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, |
if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL) == 0, |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); |
4347,7 → 4392,7 |
/* something from same cacheline, but !FORCEWAKE_MT */ |
POSTING_READ(ECOBUS); |
if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), |
if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL), |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); |
4437,16 → 4482,23 |
static void vlv_force_wake_get(struct drm_i915_private *dev_priv) |
{ |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0, |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); |
I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); |
I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, |
_MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); |
DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); |
if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_MEDIA_VLV) & |
FORCEWAKE_KERNEL), |
FORCEWAKE_ACK_TIMEOUT_MS)) |
DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); |
__gen6_gt_wait_for_thread_c0(dev_priv); |
} |
4453,8 → 4505,9 |
static void vlv_force_wake_put(struct drm_i915_private *dev_priv) |
{ |
I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); |
/* something from same cacheline, but !FORCEWAKE_VLV */ |
POSTING_READ(FORCEWAKE_ACK_VLV); |
I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, |
_MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); |
/* The below doubles as a POSTING_READ */ |
gen6_gt_check_fifodbg(dev_priv); |
} |
4539,3 → 4592,56 |
return 0; |
} |
static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, |
u8 addr, u32 *val) |
{ |
u32 cmd, devfn, port, be, bar; |
bar = 0; |
be = 0xf; |
port = IOSF_PORT_PUNIT; |
devfn = PCI_DEVFN(2, 0); |
cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | |
(port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | |
(bar << IOSF_BAR_SHIFT); |
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); |
if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) { |
DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n", |
opcode == PUNIT_OPCODE_REG_READ ? |
"read" : "write"); |
return -EAGAIN; |
} |
I915_WRITE(VLV_IOSF_ADDR, addr); |
if (opcode == PUNIT_OPCODE_REG_WRITE) |
I915_WRITE(VLV_IOSF_DATA, *val); |
I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); |
if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, |
500)) { |
DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", |
opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", |
addr); |
return -ETIMEDOUT; |
} |
if (opcode == PUNIT_OPCODE_REG_READ) |
*val = I915_READ(VLV_IOSF_DATA); |
I915_WRITE(VLV_IOSF_DATA, 0); |
return 0; |
} |
int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) |
{ |
return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_READ, addr, val); |
} |
int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) |
{ |
return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_WRITE, addr, &val); |
} |
/drivers/video/drm/i915/intel_ringbuffer.c |
---|
26,8 → 26,6 |
* Xiang Hai hao<haihao.xiang@intel.com> |
* |
*/ |
#define iowrite32(v, addr) writel((v), (addr)) |
#define ioread32(addr) readl(addr) |
#include <drm/drmP.h> |
#include "i915_drv.h" |
506,6 → 504,8 |
struct drm_i915_private *dev_priv = dev->dev_private; |
int ret = init_ring_common(ring); |
ENTER(); |
if (INTEL_INFO(dev)->gen > 3) |
I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH)); |
555,6 → 555,8 |
if (HAS_L3_GPU_CACHE(dev)) |
I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR); |
LEAVE(); |
return ret; |
} |
879,6 → 881,8 |
drm_i915_private_t *dev_priv = ring->dev->dev_private; |
u32 mmio = 0; |
ENTER(); |
/* The ring status page addresses are no longer next to the rest of |
* the ring registers as of gen7. |
*/ |
902,6 → 906,8 |
I915_WRITE(mmio, (u32)ring->status_page.gfx_addr); |
POSTING_READ(mmio); |
LEAVE(); |
} |
static int |
/drivers/video/drm/i915/intel_sdvo.c |
---|
246,11 → 246,11 |
return; |
} |
if (intel_sdvo->sdvo_reg == SDVOB) { |
cval = I915_READ(SDVOC); |
} else { |
bval = I915_READ(SDVOB); |
} |
if (intel_sdvo->sdvo_reg == GEN3_SDVOB) |
cval = I915_READ(GEN3_SDVOC); |
else |
bval = I915_READ(GEN3_SDVOB); |
/* |
* Write the registers twice for luck. Sometimes, |
* writing them only once doesn't appear to 'stick'. |
258,10 → 258,10 |
*/ |
for (i = 0; i < 2; i++) |
{ |
I915_WRITE(SDVOB, bval); |
I915_READ(SDVOB); |
I915_WRITE(SDVOC, cval); |
I915_READ(SDVOC); |
I915_WRITE(GEN3_SDVOB, bval); |
I915_READ(GEN3_SDVOB); |
I915_WRITE(GEN3_SDVOC, cval); |
I915_READ(GEN3_SDVOC); |
} |
} |
451,7 → 451,7 |
int i, ret = true; |
/* Would be simpler to allocate both in one go ? */ |
buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL); |
buf = kzalloc(args_len * 2 + 2, GFP_KERNEL); |
if (!buf) |
return false; |
788,7 → 788,6 |
v_sync_offset = mode->vsync_start - mode->vdisplay; |
mode_clock = mode->clock; |
mode_clock /= intel_mode_get_pixel_multiplier(mode) ?: 1; |
mode_clock /= 10; |
dtd->part1.clock = mode_clock; |
957,14 → 956,17 |
.len = DIP_LEN_AVI, |
}; |
uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; |
struct intel_crtc *intel_crtc = to_intel_crtc(intel_sdvo->base.base.crtc); |
if (intel_sdvo->rgb_quant_range_selectable) { |
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) |
if (intel_crtc->config.limited_color_range) |
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; |
else |
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; |
} |
avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); |
intel_dip_infoframe_csum(&avi_if); |
/* sdvo spec says that the ecc is handled by the hw, and it looks like |
1039,13 → 1041,19 |
return true; |
} |
static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static bool intel_sdvo_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); |
int multiplier; |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
struct drm_display_mode *mode = &pipe_config->requested_mode; |
DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n"); |
pipe_config->pipe_bpp = 8*3; |
if (HAS_PCH_SPLIT(encoder->base.dev)) |
pipe_config->has_pch_encoder = true; |
/* We need to construct preferred input timings based on our |
* output timings. To do that, we have to set the output |
* timings, even though this isn't really the right place in |
1071,37 → 1079,40 |
/* Make the CRTC code factor in the SDVO pixel multiplier. The |
* SDVO device will factor out the multiplier during mode_set. |
*/ |
multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); |
intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); |
pipe_config->pixel_multiplier = |
intel_sdvo_get_pixel_multiplier(adjusted_mode); |
adjusted_mode->clock *= pipe_config->pixel_multiplier; |
if (intel_sdvo->color_range_auto) { |
/* See CEA-861-E - 5.1 Default Encoding Parameters */ |
/* FIXME: This bit is only valid when using TMDS encoding and 8 |
* bit per color mode. */ |
if (intel_sdvo->has_hdmi_monitor && |
drm_match_cea_mode(adjusted_mode) > 1) |
intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; |
intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; |
else |
intel_sdvo->color_range = 0; |
} |
if (intel_sdvo->color_range) |
adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; |
pipe_config->limited_color_range = true; |
return true; |
} |
static void intel_sdvo_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_device *dev = intel_encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_crtc *crtc = encoder->crtc; |
struct drm_crtc *crtc = intel_encoder->base.crtc; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
struct drm_display_mode *mode = &intel_crtc->config.requested_mode; |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&intel_encoder->base); |
u32 sdvox; |
struct intel_sdvo_in_out_map in_out; |
struct intel_sdvo_dtd input_dtd, output_dtd; |
int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); |
int rate; |
if (!mode) |
1161,7 → 1172,7 |
DRM_INFO("Setting input timings on %s failed\n", |
SDVO_NAME(intel_sdvo)); |
switch (pixel_multiplier) { |
switch (intel_crtc->config.pixel_multiplier) { |
default: |
case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; |
case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; |
1182,10 → 1193,10 |
} else { |
sdvox = I915_READ(intel_sdvo->sdvo_reg); |
switch (intel_sdvo->sdvo_reg) { |
case SDVOB: |
case GEN3_SDVOB: |
sdvox &= SDVOB_PRESERVE_MASK; |
break; |
case SDVOC: |
case GEN3_SDVOC: |
sdvox &= SDVOC_PRESERVE_MASK; |
break; |
} |
1193,9 → 1204,9 |
} |
if (INTEL_PCH_TYPE(dev) >= PCH_CPT) |
sdvox |= TRANSCODER_CPT(intel_crtc->pipe); |
sdvox |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); |
else |
sdvox |= TRANSCODER(intel_crtc->pipe); |
sdvox |= SDVO_PIPE_SEL(intel_crtc->pipe); |
if (intel_sdvo->has_hdmi_audio) |
sdvox |= SDVO_AUDIO_ENABLE; |
1205,7 → 1216,8 |
} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { |
/* done in crtc_mode_set as it lives inside the dpll register */ |
} else { |
sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT; |
sdvox |= (intel_crtc->config.pixel_multiplier - 1) |
<< SDVO_PORT_MULTIPLY_SHIFT; |
} |
if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL && |
1235,11 → 1247,13 |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
u16 active_outputs; |
u32 tmp; |
tmp = I915_READ(intel_sdvo->sdvo_reg); |
intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); |
if (!(tmp & SDVO_ENABLE)) |
if (!(tmp & SDVO_ENABLE) && (active_outputs == 0)) |
return false; |
if (HAS_PCH_CPT(dev)) |
1305,16 → 1319,10 |
temp = I915_READ(intel_sdvo->sdvo_reg); |
if ((temp & SDVO_ENABLE) == 0) { |
/* HW workaround for IBX, we need to move the port |
* to transcoder A before disabling it. */ |
if (HAS_PCH_IBX(dev)) { |
struct drm_crtc *crtc = encoder->base.crtc; |
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; |
* to transcoder A before disabling it, so restore it here. */ |
if (HAS_PCH_IBX(dev)) |
temp |= SDVO_PIPE_SEL(intel_crtc->pipe); |
/* Restore the transcoder select bit. */ |
if (pipe == PIPE_B) |
temp |= SDVO_PIPE_B_SELECT; |
} |
intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); |
} |
for (i = 0; i < 2; i++) |
1768,11 → 1776,14 |
* Assume that the preferred modes are |
* arranged in priority order. |
*/ |
intel_ddc_get_modes(connector, intel_sdvo->i2c); |
if (list_empty(&connector->probed_modes) == false) |
goto end; |
intel_ddc_get_modes(connector, &intel_sdvo->ddc); |
/* Fetch modes from VBT */ |
/* |
* Fetch modes from VBT. For SDVO prefer the VBT mode since some |
* SDVO->LVDS transcoders can't cope with the EDID mode. Since |
* drm_mode_probed_add adds the mode at the head of the list we add it |
* last. |
*/ |
if (dev_priv->sdvo_lvds_vbt_mode != NULL) { |
newmode = drm_mode_duplicate(connector->dev, |
dev_priv->sdvo_lvds_vbt_mode); |
1784,7 → 1795,6 |
} |
} |
end: |
list_for_each_entry(newmode, &connector->probed_modes, head) { |
if (newmode->type & DRM_MODE_TYPE_PREFERRED) { |
intel_sdvo->sdvo_lvds_fixed_mode = |
1922,6 → 1932,9 |
} |
if (property == dev_priv->broadcast_rgb_property) { |
bool old_auto = intel_sdvo->color_range_auto; |
uint32_t old_range = intel_sdvo->color_range; |
switch (val) { |
case INTEL_BROADCAST_RGB_AUTO: |
intel_sdvo->color_range_auto = true; |
1932,11 → 1945,18 |
break; |
case INTEL_BROADCAST_RGB_LIMITED: |
intel_sdvo->color_range_auto = false; |
intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; |
/* FIXME: this bit is only valid when using TMDS |
* encoding and 8 bit per color mode. */ |
intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; |
break; |
default: |
return -EINVAL; |
} |
if (old_auto == intel_sdvo->color_range_auto && |
old_range == intel_sdvo->color_range) |
return 0; |
goto done; |
} |
2040,11 → 2060,6 |
#undef CHECK_PROPERTY |
} |
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { |
.mode_fixup = intel_sdvo_mode_fixup, |
.mode_set = intel_sdvo_mode_set, |
}; |
static const struct drm_connector_funcs intel_sdvo_connector_funcs = { |
.dpms = intel_sdvo_dpms, |
.detect = intel_sdvo_detect, |
2269,7 → 2284,6 |
connector = &intel_connector->base; |
if (intel_sdvo_get_hotplug_support(intel_sdvo) & |
intel_sdvo_connector->output_flag) { |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag; |
/* Some SDVO devices have one-shot hotplug interrupts. |
* Ensure that they get re-enabled when an interrupt happens. |
2277,7 → 2291,7 |
intel_encoder->hot_plug = intel_sdvo_enable_hotplug; |
intel_sdvo_enable_hotplug(intel_encoder); |
} else { |
connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; |
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; |
} |
encoder->encoder_type = DRM_MODE_ENCODER_TMDS; |
connector->connector_type = DRM_MODE_CONNECTOR_DVID; |
2346,7 → 2360,7 |
intel_connector = &intel_sdvo_connector->base; |
connector = &intel_connector->base; |
connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
encoder->encoder_type = DRM_MODE_ENCODER_DAC; |
connector->connector_type = DRM_MODE_CONNECTOR_VGA; |
2739,7 → 2753,6 |
struct intel_sdvo *intel_sdvo; |
u32 hotplug_mask; |
int i; |
intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); |
if (!intel_sdvo) |
return false; |
2779,9 → 2792,9 |
SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; |
} |
drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); |
intel_encoder->compute_config = intel_sdvo_compute_config; |
intel_encoder->disable = intel_disable_sdvo; |
intel_encoder->mode_set = intel_sdvo_mode_set; |
intel_encoder->enable = intel_enable_sdvo; |
intel_encoder->get_hw_state = intel_sdvo_get_hw_state; |
2797,6 → 2810,14 |
goto err_output; |
} |
/* Only enable the hotplug irq if we need it, to work around noisy |
* hotplug lines. |
*/ |
if (intel_sdvo->hotplug_active) { |
intel_encoder->hpd_pin = |
intel_sdvo->is_sdvob ? HPD_SDVO_B : HPD_SDVO_C; |
} |
/* |
* Cloning SDVO with anything is often impossible, since the SDVO |
* encoder can request a special input timing mode. And even if that's |
2807,12 → 2828,6 |
*/ |
intel_sdvo->base.cloneable = false; |
/* Only enable the hotplug irq if we need it, to work around noisy |
* hotplug lines. |
*/ |
if (intel_sdvo->hotplug_active) |
dev_priv->hotplug_supported_mask |= hotplug_mask; |
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); |
/* Set the input timing to the screen. Assume always input 0. */ |
/drivers/video/drm/i915/intel_sprite.c |
---|
37,6 → 37,174 |
#include "i915_drv.h" |
static void |
vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb, |
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, |
unsigned int crtc_w, unsigned int crtc_h, |
uint32_t x, uint32_t y, |
uint32_t src_w, uint32_t src_h) |
{ |
struct drm_device *dev = dplane->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_plane *intel_plane = to_intel_plane(dplane); |
int pipe = intel_plane->pipe; |
int plane = intel_plane->plane; |
u32 sprctl; |
unsigned long sprsurf_offset, linear_offset; |
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); |
sprctl = I915_READ(SPCNTR(pipe, plane)); |
/* Mask out pixel format bits in case we change it */ |
sprctl &= ~SP_PIXFORMAT_MASK; |
sprctl &= ~SP_YUV_BYTE_ORDER_MASK; |
sprctl &= ~SP_TILED; |
switch (fb->pixel_format) { |
case DRM_FORMAT_YUYV: |
sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; |
break; |
case DRM_FORMAT_YVYU: |
sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; |
break; |
case DRM_FORMAT_UYVY: |
sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; |
break; |
case DRM_FORMAT_VYUY: |
sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; |
break; |
case DRM_FORMAT_RGB565: |
sprctl |= SP_FORMAT_BGR565; |
break; |
case DRM_FORMAT_XRGB8888: |
sprctl |= SP_FORMAT_BGRX8888; |
break; |
case DRM_FORMAT_ARGB8888: |
sprctl |= SP_FORMAT_BGRA8888; |
break; |
case DRM_FORMAT_XBGR2101010: |
sprctl |= SP_FORMAT_RGBX1010102; |
break; |
case DRM_FORMAT_ABGR2101010: |
sprctl |= SP_FORMAT_RGBA1010102; |
break; |
case DRM_FORMAT_XBGR8888: |
sprctl |= SP_FORMAT_RGBX8888; |
break; |
case DRM_FORMAT_ABGR8888: |
sprctl |= SP_FORMAT_RGBA8888; |
break; |
default: |
/* |
* If we get here one of the upper layers failed to filter |
* out the unsupported plane formats |
*/ |
BUG(); |
break; |
} |
if (obj->tiling_mode != I915_TILING_NONE) |
sprctl |= SP_TILED; |
sprctl |= SP_ENABLE; |
/* Sizes are 0 based */ |
src_w--; |
src_h--; |
crtc_w--; |
crtc_h--; |
intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); |
I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); |
I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); |
linear_offset = y * fb->pitches[0] + x * pixel_size; |
sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, |
obj->tiling_mode, |
pixel_size, |
fb->pitches[0]); |
linear_offset -= sprsurf_offset; |
if (obj->tiling_mode != I915_TILING_NONE) |
I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); |
else |
I915_WRITE(SPLINOFF(pipe, plane), linear_offset); |
I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); |
I915_WRITE(SPCNTR(pipe, plane), sprctl); |
I915_MODIFY_DISPBASE(SPSURF(pipe, plane), obj->gtt_offset + |
sprsurf_offset); |
POSTING_READ(SPSURF(pipe, plane)); |
} |
static void |
vlv_disable_plane(struct drm_plane *dplane) |
{ |
struct drm_device *dev = dplane->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_plane *intel_plane = to_intel_plane(dplane); |
int pipe = intel_plane->pipe; |
int plane = intel_plane->plane; |
I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & |
~SP_ENABLE); |
/* Activate double buffered register update */ |
I915_MODIFY_DISPBASE(SPSURF(pipe, plane), 0); |
POSTING_READ(SPSURF(pipe, plane)); |
} |
static int |
vlv_update_colorkey(struct drm_plane *dplane, |
struct drm_intel_sprite_colorkey *key) |
{ |
struct drm_device *dev = dplane->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_plane *intel_plane = to_intel_plane(dplane); |
int pipe = intel_plane->pipe; |
int plane = intel_plane->plane; |
u32 sprctl; |
if (key->flags & I915_SET_COLORKEY_DESTINATION) |
return -EINVAL; |
I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); |
I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); |
I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); |
sprctl = I915_READ(SPCNTR(pipe, plane)); |
sprctl &= ~SP_SOURCE_KEY; |
if (key->flags & I915_SET_COLORKEY_SOURCE) |
sprctl |= SP_SOURCE_KEY; |
I915_WRITE(SPCNTR(pipe, plane), sprctl); |
POSTING_READ(SPKEYMSK(pipe, plane)); |
return 0; |
} |
static void |
vlv_get_colorkey(struct drm_plane *dplane, |
struct drm_intel_sprite_colorkey *key) |
{ |
struct drm_device *dev = dplane->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_plane *intel_plane = to_intel_plane(dplane); |
int pipe = intel_plane->pipe; |
int plane = intel_plane->plane; |
u32 sprctl; |
key->min_value = I915_READ(SPKEYMINVAL(pipe, plane)); |
key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane)); |
key->channel_mask = I915_READ(SPKEYMSK(pipe, plane)); |
sprctl = I915_READ(SPCNTR(pipe, plane)); |
if (sprctl & SP_SOURCE_KEY) |
key->flags = I915_SET_COLORKEY_SOURCE; |
else |
key->flags = I915_SET_COLORKEY_NONE; |
} |
static void |
ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, |
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, |
unsigned int crtc_w, unsigned int crtc_h, |
441,6 → 609,15 |
old_obj = intel_plane->obj; |
intel_plane->crtc_x = crtc_x; |
intel_plane->crtc_y = crtc_y; |
intel_plane->crtc_w = crtc_w; |
intel_plane->crtc_h = crtc_h; |
intel_plane->src_x = src_x; |
intel_plane->src_y = src_y; |
intel_plane->src_w = src_w; |
intel_plane->src_h = src_h; |
src_w = src_w >> 16; |
src_h = src_h >> 16; |
513,6 → 690,11 |
mutex_lock(&dev->struct_mutex); |
/* Note that this will apply the VT-d workaround for scanouts, |
* which is more restrictive than required for sprites. (The |
* primary plane requires 256KiB alignment with 64 PTE padding, |
* the sprite planes only require 128KiB alignment and 32 PTE padding. |
*/ |
ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); |
if (ret) |
goto out_unlock; |
568,6 → 750,8 |
if (!intel_plane->obj) |
goto out; |
intel_wait_for_vblank(dev, intel_plane->pipe); |
mutex_lock(&dev->struct_mutex); |
intel_unpin_fb_obj(intel_plane->obj); |
intel_plane->obj = NULL; |
647,6 → 831,20 |
return ret; |
} |
void intel_plane_restore(struct drm_plane *plane) |
{ |
struct intel_plane *intel_plane = to_intel_plane(plane); |
if (!plane->crtc || !plane->fb) |
return; |
intel_update_plane(plane, plane->crtc, plane->fb, |
intel_plane->crtc_x, intel_plane->crtc_y, |
intel_plane->crtc_w, intel_plane->crtc_h, |
intel_plane->src_x, intel_plane->src_y, |
intel_plane->src_w, intel_plane->src_h); |
} |
static const struct drm_plane_funcs intel_plane_funcs = { |
.update_plane = intel_update_plane, |
.disable_plane = intel_disable_plane, |
670,8 → 868,22 |
DRM_FORMAT_VYUY, |
}; |
static uint32_t vlv_plane_formats[] = { |
DRM_FORMAT_RGB565, |
DRM_FORMAT_ABGR8888, |
DRM_FORMAT_ARGB8888, |
DRM_FORMAT_XBGR8888, |
DRM_FORMAT_XRGB8888, |
DRM_FORMAT_XBGR2101010, |
DRM_FORMAT_ABGR2101010, |
DRM_FORMAT_YUYV, |
DRM_FORMAT_YVYU, |
DRM_FORMAT_UYVY, |
DRM_FORMAT_VYUY, |
}; |
int |
intel_plane_init(struct drm_device *dev, enum pipe pipe) |
intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) |
{ |
struct intel_plane *intel_plane; |
unsigned long possible_crtcs; |
710,6 → 922,17 |
intel_plane->can_scale = false; |
else |
intel_plane->can_scale = true; |
if (IS_VALLEYVIEW(dev)) { |
intel_plane->max_downscale = 1; |
intel_plane->update_plane = vlv_update_plane; |
intel_plane->disable_plane = vlv_disable_plane; |
intel_plane->update_colorkey = vlv_update_colorkey; |
intel_plane->get_colorkey = vlv_get_colorkey; |
plane_formats = vlv_plane_formats; |
num_plane_formats = ARRAY_SIZE(vlv_plane_formats); |
} else { |
intel_plane->max_downscale = 2; |
intel_plane->update_plane = ivb_update_plane; |
intel_plane->disable_plane = ivb_disable_plane; |
718,6 → 941,7 |
plane_formats = snb_plane_formats; |
num_plane_formats = ARRAY_SIZE(snb_plane_formats); |
} |
break; |
default: |
726,6 → 950,7 |
} |
intel_plane->pipe = pipe; |
intel_plane->plane = plane; |
possible_crtcs = (1 << pipe); |
ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, |
&intel_plane_funcs, |