Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel: drm/i915: hold ref on flip object until it completes drm/i915: Fix crash while aborting hibernation drm/i915: Correctly return -ENOMEM on allocation failure in cmdbuf ioctls. drm/i915: fix pipe source image setting in flip command drm/i915: fix flip done interrupt on Ironlake drm/i915: untangle page flip completion drm/i915: handle FBC and self-refresh better drm/i915: Increase fb alignment to 64k drm/i915: Update write_domains on active list after flush. drm/i915: Rework DPLL calculation parameters for Ironlake
This commit is contained in:
commit
26b23ace8b
8 changed files with 339 additions and 149 deletions
|
@ -735,8 +735,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
|
|||
if (cmdbuf->num_cliprects) {
|
||||
cliprects = kcalloc(cmdbuf->num_cliprects,
|
||||
sizeof(struct drm_clip_rect), GFP_KERNEL);
|
||||
if (cliprects == NULL)
|
||||
if (cliprects == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_batch_free;
|
||||
}
|
||||
|
||||
ret = copy_from_user(cliprects, cmdbuf->cliprects,
|
||||
cmdbuf->num_cliprects *
|
||||
|
|
|
@ -174,12 +174,42 @@ const static struct pci_device_id pciidlist[] = {
|
|||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||
#endif
|
||||
|
||||
static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
||||
static int i915_drm_freeze(struct drm_device *dev)
|
||||
{
|
||||
pci_save_state(dev->pdev);
|
||||
|
||||
/* If KMS is active, we do the leavevt stuff here */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
int error = i915_gem_idle(dev);
|
||||
if (error) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
"GEM idle failed, resume might fail\n");
|
||||
return error;
|
||||
}
|
||||
drm_irq_uninstall(dev);
|
||||
}
|
||||
|
||||
i915_save_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_drm_suspend(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (!dev || !dev_priv) {
|
||||
DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
|
||||
intel_opregion_free(dev, 1);
|
||||
|
||||
/* Modeset on resume, not lid events */
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
}
|
||||
|
||||
static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!dev || !dev->dev_private) {
|
||||
DRM_ERROR("dev: %p\n", dev);
|
||||
DRM_ERROR("DRM not initialized, aborting suspend.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -187,19 +217,11 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
if (state.event == PM_EVENT_PRETHAW)
|
||||
return 0;
|
||||
|
||||
pci_save_state(dev->pdev);
|
||||
error = i915_drm_freeze(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* If KMS is active, we do the leavevt stuff here */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
if (i915_gem_idle(dev))
|
||||
dev_err(&dev->pdev->dev,
|
||||
"GEM idle failed, resume may fail\n");
|
||||
drm_irq_uninstall(dev);
|
||||
}
|
||||
|
||||
i915_save_state(dev);
|
||||
|
||||
intel_opregion_free(dev, 1);
|
||||
i915_drm_suspend(dev);
|
||||
|
||||
if (state.event == PM_EVENT_SUSPEND) {
|
||||
/* Shut down the device */
|
||||
|
@ -207,45 +229,45 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
pci_set_power_state(dev->pdev, PCI_D3hot);
|
||||
}
|
||||
|
||||
/* Modeset on resume, not lid events */
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_resume(struct drm_device *dev)
|
||||
static int i915_drm_thaw(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret = 0;
|
||||
|
||||
if (pci_enable_device(dev->pdev))
|
||||
return -1;
|
||||
pci_set_master(dev->pdev);
|
||||
|
||||
i915_restore_state(dev);
|
||||
|
||||
intel_opregion_init(dev, 1);
|
||||
int error = 0;
|
||||
|
||||
/* KMS EnterVT equivalent */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
ret = i915_gem_init_ringbuffer(dev);
|
||||
if (ret != 0)
|
||||
ret = -1;
|
||||
error = i915_gem_init_ringbuffer(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_irq_install(dev);
|
||||
}
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
|
||||
/* Resume the modeset for every activated CRTC */
|
||||
drm_helper_resume_force_mode(dev);
|
||||
}
|
||||
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
return ret;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int i915_resume(struct drm_device *dev)
|
||||
{
|
||||
if (pci_enable_device(dev->pdev))
|
||||
return -EIO;
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
|
||||
i915_restore_state(dev);
|
||||
|
||||
intel_opregion_init(dev, 1);
|
||||
|
||||
return i915_drm_thaw(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -386,57 +408,69 @@ i915_pci_remove(struct pci_dev *pdev)
|
|||
drm_put_dev(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
static int i915_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
int error;
|
||||
|
||||
return i915_suspend(dev, state);
|
||||
}
|
||||
if (!drm_dev || !drm_dev->dev_private) {
|
||||
dev_err(dev, "DRM not initialized, aborting suspend.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_pci_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
error = i915_drm_freeze(drm_dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return i915_resume(dev);
|
||||
}
|
||||
i915_drm_suspend(drm_dev);
|
||||
|
||||
static int
|
||||
i915_pm_suspend(struct device *dev)
|
||||
{
|
||||
return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND);
|
||||
}
|
||||
pci_disable_device(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
|
||||
static int
|
||||
i915_pm_resume(struct device *dev)
|
||||
{
|
||||
return i915_pci_resume(to_pci_dev(dev));
|
||||
}
|
||||
|
||||
static int
|
||||
i915_pm_freeze(struct device *dev)
|
||||
{
|
||||
return i915_pci_suspend(to_pci_dev(dev), PMSG_FREEZE);
|
||||
}
|
||||
|
||||
static int
|
||||
i915_pm_thaw(struct device *dev)
|
||||
{
|
||||
/* thaw during hibernate, do nothing! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_pm_poweroff(struct device *dev)
|
||||
static int i915_pm_resume(struct device *dev)
|
||||
{
|
||||
return i915_pci_suspend(to_pci_dev(dev), PMSG_HIBERNATE);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
|
||||
return i915_resume(drm_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
i915_pm_restore(struct device *dev)
|
||||
static int i915_pm_freeze(struct device *dev)
|
||||
{
|
||||
return i915_pci_resume(to_pci_dev(dev));
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
|
||||
if (!drm_dev || !drm_dev->dev_private) {
|
||||
dev_err(dev, "DRM not initialized, aborting suspend.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return i915_drm_freeze(drm_dev);
|
||||
}
|
||||
|
||||
static int i915_pm_thaw(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
|
||||
return i915_drm_thaw(drm_dev);
|
||||
}
|
||||
|
||||
static int i915_pm_poweroff(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
int error;
|
||||
|
||||
error = i915_drm_freeze(drm_dev);
|
||||
if (!error)
|
||||
i915_drm_suspend(drm_dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops i915_pm_ops = {
|
||||
|
@ -445,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = {
|
|||
.freeze = i915_pm_freeze,
|
||||
.thaw = i915_pm_thaw,
|
||||
.poweroff = i915_pm_poweroff,
|
||||
.restore = i915_pm_restore,
|
||||
.restore = i915_pm_resume,
|
||||
};
|
||||
|
||||
static struct vm_operations_struct i915_gem_vm_ops = {
|
||||
|
|
|
@ -492,6 +492,15 @@ typedef struct drm_i915_private {
|
|||
*/
|
||||
struct list_head flushing_list;
|
||||
|
||||
/**
|
||||
* List of objects currently pending a GPU write flush.
|
||||
*
|
||||
* All elements on this list will belong to either the
|
||||
* active_list or flushing_list, last_rendering_seqno can
|
||||
* be used to differentiate between the two elements.
|
||||
*/
|
||||
struct list_head gpu_write_list;
|
||||
|
||||
/**
|
||||
* LRU list of objects which are not in the ringbuffer and
|
||||
* are ready to unbind, but are still in the GTT.
|
||||
|
@ -592,6 +601,8 @@ struct drm_i915_gem_object {
|
|||
|
||||
/** This object's place on the active/flushing/inactive lists */
|
||||
struct list_head list;
|
||||
/** This object's place on GPU write list */
|
||||
struct list_head gpu_write_list;
|
||||
|
||||
/** This object's place on the fenced object LRU */
|
||||
struct list_head fence_list;
|
||||
|
|
|
@ -1552,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
|
|||
else
|
||||
list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
|
||||
|
||||
BUG_ON(!list_empty(&obj_priv->gpu_write_list));
|
||||
|
||||
obj_priv->last_rendering_seqno = 0;
|
||||
if (obj_priv->active) {
|
||||
obj_priv->active = 0;
|
||||
|
@ -1622,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
|
|||
struct drm_i915_gem_object *obj_priv, *next;
|
||||
|
||||
list_for_each_entry_safe(obj_priv, next,
|
||||
&dev_priv->mm.flushing_list, list) {
|
||||
&dev_priv->mm.gpu_write_list,
|
||||
gpu_write_list) {
|
||||
struct drm_gem_object *obj = obj_priv->obj;
|
||||
|
||||
if ((obj->write_domain & flush_domains) ==
|
||||
|
@ -1630,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
|
|||
uint32_t old_write_domain = obj->write_domain;
|
||||
|
||||
obj->write_domain = 0;
|
||||
list_del_init(&obj_priv->gpu_write_list);
|
||||
i915_gem_object_move_to_active(obj, seqno);
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
|
@ -2084,8 +2088,8 @@ static int
|
|||
i915_gem_evict_everything(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t seqno;
|
||||
int ret;
|
||||
uint32_t seqno;
|
||||
bool lists_empty;
|
||||
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
|
@ -2107,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
|
||||
|
||||
ret = i915_gem_evict_from_inactive_list(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -2701,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
|
|||
old_write_domain = obj->write_domain;
|
||||
i915_gem_flush(dev, 0, obj->write_domain);
|
||||
seqno = i915_add_request(dev, NULL, obj->write_domain);
|
||||
obj->write_domain = 0;
|
||||
BUG_ON(obj->write_domain);
|
||||
i915_gem_object_move_to_active(obj, seqno);
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
|
@ -3682,8 +3688,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||
if (args->num_cliprects != 0) {
|
||||
cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects),
|
||||
GFP_KERNEL);
|
||||
if (cliprects == NULL)
|
||||
if (cliprects == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto pre_mutex_err;
|
||||
}
|
||||
|
||||
ret = copy_from_user(cliprects,
|
||||
(struct drm_clip_rect __user *)
|
||||
|
@ -3850,16 +3858,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||
i915_gem_flush(dev,
|
||||
dev->invalidate_domains,
|
||||
dev->flush_domains);
|
||||
if (dev->flush_domains)
|
||||
if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
|
||||
(void)i915_add_request(dev, file_priv,
|
||||
dev->flush_domains);
|
||||
}
|
||||
|
||||
for (i = 0; i < args->buffer_count; i++) {
|
||||
struct drm_gem_object *obj = object_list[i];
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
uint32_t old_write_domain = obj->write_domain;
|
||||
|
||||
obj->write_domain = obj->pending_write_domain;
|
||||
if (obj->write_domain)
|
||||
list_move_tail(&obj_priv->gpu_write_list,
|
||||
&dev_priv->mm.gpu_write_list);
|
||||
else
|
||||
list_del_init(&obj_priv->gpu_write_list);
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
obj->read_domains,
|
||||
old_write_domain);
|
||||
|
@ -4370,6 +4385,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
|||
obj_priv->obj = obj;
|
||||
obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
INIT_LIST_HEAD(&obj_priv->list);
|
||||
INIT_LIST_HEAD(&obj_priv->gpu_write_list);
|
||||
INIT_LIST_HEAD(&obj_priv->fence_list);
|
||||
obj_priv->madv = I915_MADV_WILLNEED;
|
||||
|
||||
|
@ -4821,6 +4837,7 @@ i915_gem_load(struct drm_device *dev)
|
|||
spin_lock_init(&dev_priv->mm.active_list_lock);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.active_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.request_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
|
||||
|
|
|
@ -309,22 +309,22 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
|
|||
if (de_iir & DE_GSE)
|
||||
ironlake_opregion_gse_intr(dev);
|
||||
|
||||
if (de_iir & DE_PLANEA_FLIP_DONE)
|
||||
if (de_iir & DE_PLANEA_FLIP_DONE) {
|
||||
intel_prepare_page_flip(dev, 0);
|
||||
|
||||
if (de_iir & DE_PLANEB_FLIP_DONE)
|
||||
intel_prepare_page_flip(dev, 1);
|
||||
|
||||
if (de_iir & DE_PIPEA_VBLANK) {
|
||||
drm_handle_vblank(dev, 0);
|
||||
intel_finish_page_flip(dev, 0);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PIPEB_VBLANK) {
|
||||
drm_handle_vblank(dev, 1);
|
||||
if (de_iir & DE_PLANEB_FLIP_DONE) {
|
||||
intel_prepare_page_flip(dev, 1);
|
||||
intel_finish_page_flip(dev, 1);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PIPEA_VBLANK)
|
||||
drm_handle_vblank(dev, 0);
|
||||
|
||||
if (de_iir & DE_PIPEB_VBLANK)
|
||||
drm_handle_vblank(dev, 1);
|
||||
|
||||
/* check event from PCH */
|
||||
if ((de_iir & DE_PCH_EVENT) &&
|
||||
(pch_iir & SDE_HOTPLUG_MASK)) {
|
||||
|
|
|
@ -338,6 +338,7 @@
|
|||
#define FBC_CTL_PERIODIC (1<<30)
|
||||
#define FBC_CTL_INTERVAL_SHIFT (16)
|
||||
#define FBC_CTL_UNCOMPRESSIBLE (1<<14)
|
||||
#define FBC_C3_IDLE (1<<13)
|
||||
#define FBC_CTL_STRIDE_SHIFT (5)
|
||||
#define FBC_CTL_FENCENO (1<<0)
|
||||
#define FBC_COMMAND 0x0320c
|
||||
|
|
|
@ -240,33 +240,86 @@ struct intel_limit {
|
|||
#define IRONLAKE_DOT_MAX 350000
|
||||
#define IRONLAKE_VCO_MIN 1760000
|
||||
#define IRONLAKE_VCO_MAX 3510000
|
||||
#define IRONLAKE_N_MIN 1
|
||||
#define IRONLAKE_N_MAX 6
|
||||
#define IRONLAKE_M_MIN 79
|
||||
#define IRONLAKE_M_MAX 127
|
||||
#define IRONLAKE_M1_MIN 12
|
||||
#define IRONLAKE_M1_MAX 22
|
||||
#define IRONLAKE_M2_MIN 5
|
||||
#define IRONLAKE_M2_MAX 9
|
||||
#define IRONLAKE_P_SDVO_DAC_MIN 5
|
||||
#define IRONLAKE_P_SDVO_DAC_MAX 80
|
||||
#define IRONLAKE_P_LVDS_MIN 28
|
||||
#define IRONLAKE_P_LVDS_MAX 112
|
||||
#define IRONLAKE_P1_MIN 1
|
||||
#define IRONLAKE_P1_MAX 8
|
||||
#define IRONLAKE_P2_SDVO_DAC_SLOW 10
|
||||
#define IRONLAKE_P2_SDVO_DAC_FAST 5
|
||||
#define IRONLAKE_P2_LVDS_SLOW 14 /* single channel */
|
||||
#define IRONLAKE_P2_LVDS_FAST 7 /* double channel */
|
||||
#define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */
|
||||
|
||||
#define IRONLAKE_P_DISPLAY_PORT_MIN 10
|
||||
#define IRONLAKE_P_DISPLAY_PORT_MAX 20
|
||||
#define IRONLAKE_P2_DISPLAY_PORT_FAST 10
|
||||
#define IRONLAKE_P2_DISPLAY_PORT_SLOW 10
|
||||
#define IRONLAKE_P2_DISPLAY_PORT_LIMIT 0
|
||||
#define IRONLAKE_P1_DISPLAY_PORT_MIN 1
|
||||
#define IRONLAKE_P1_DISPLAY_PORT_MAX 2
|
||||
/* We have parameter ranges for different type of outputs. */
|
||||
|
||||
/* DAC & HDMI Refclk 120Mhz */
|
||||
#define IRONLAKE_DAC_N_MIN 1
|
||||
#define IRONLAKE_DAC_N_MAX 5
|
||||
#define IRONLAKE_DAC_M_MIN 79
|
||||
#define IRONLAKE_DAC_M_MAX 127
|
||||
#define IRONLAKE_DAC_P_MIN 5
|
||||
#define IRONLAKE_DAC_P_MAX 80
|
||||
#define IRONLAKE_DAC_P1_MIN 1
|
||||
#define IRONLAKE_DAC_P1_MAX 8
|
||||
#define IRONLAKE_DAC_P2_SLOW 10
|
||||
#define IRONLAKE_DAC_P2_FAST 5
|
||||
|
||||
/* LVDS single-channel 120Mhz refclk */
|
||||
#define IRONLAKE_LVDS_S_N_MIN 1
|
||||
#define IRONLAKE_LVDS_S_N_MAX 3
|
||||
#define IRONLAKE_LVDS_S_M_MIN 79
|
||||
#define IRONLAKE_LVDS_S_M_MAX 118
|
||||
#define IRONLAKE_LVDS_S_P_MIN 28
|
||||
#define IRONLAKE_LVDS_S_P_MAX 112
|
||||
#define IRONLAKE_LVDS_S_P1_MIN 2
|
||||
#define IRONLAKE_LVDS_S_P1_MAX 8
|
||||
#define IRONLAKE_LVDS_S_P2_SLOW 14
|
||||
#define IRONLAKE_LVDS_S_P2_FAST 14
|
||||
|
||||
/* LVDS dual-channel 120Mhz refclk */
|
||||
#define IRONLAKE_LVDS_D_N_MIN 1
|
||||
#define IRONLAKE_LVDS_D_N_MAX 3
|
||||
#define IRONLAKE_LVDS_D_M_MIN 79
|
||||
#define IRONLAKE_LVDS_D_M_MAX 127
|
||||
#define IRONLAKE_LVDS_D_P_MIN 14
|
||||
#define IRONLAKE_LVDS_D_P_MAX 56
|
||||
#define IRONLAKE_LVDS_D_P1_MIN 2
|
||||
#define IRONLAKE_LVDS_D_P1_MAX 8
|
||||
#define IRONLAKE_LVDS_D_P2_SLOW 7
|
||||
#define IRONLAKE_LVDS_D_P2_FAST 7
|
||||
|
||||
/* LVDS single-channel 100Mhz refclk */
|
||||
#define IRONLAKE_LVDS_S_SSC_N_MIN 1
|
||||
#define IRONLAKE_LVDS_S_SSC_N_MAX 2
|
||||
#define IRONLAKE_LVDS_S_SSC_M_MIN 79
|
||||
#define IRONLAKE_LVDS_S_SSC_M_MAX 126
|
||||
#define IRONLAKE_LVDS_S_SSC_P_MIN 28
|
||||
#define IRONLAKE_LVDS_S_SSC_P_MAX 112
|
||||
#define IRONLAKE_LVDS_S_SSC_P1_MIN 2
|
||||
#define IRONLAKE_LVDS_S_SSC_P1_MAX 8
|
||||
#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14
|
||||
#define IRONLAKE_LVDS_S_SSC_P2_FAST 14
|
||||
|
||||
/* LVDS dual-channel 100Mhz refclk */
|
||||
#define IRONLAKE_LVDS_D_SSC_N_MIN 1
|
||||
#define IRONLAKE_LVDS_D_SSC_N_MAX 3
|
||||
#define IRONLAKE_LVDS_D_SSC_M_MIN 79
|
||||
#define IRONLAKE_LVDS_D_SSC_M_MAX 126
|
||||
#define IRONLAKE_LVDS_D_SSC_P_MIN 14
|
||||
#define IRONLAKE_LVDS_D_SSC_P_MAX 42
|
||||
#define IRONLAKE_LVDS_D_SSC_P1_MIN 2
|
||||
#define IRONLAKE_LVDS_D_SSC_P1_MAX 6
|
||||
#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7
|
||||
#define IRONLAKE_LVDS_D_SSC_P2_FAST 7
|
||||
|
||||
/* DisplayPort */
|
||||
#define IRONLAKE_DP_N_MIN 1
|
||||
#define IRONLAKE_DP_N_MAX 2
|
||||
#define IRONLAKE_DP_M_MIN 81
|
||||
#define IRONLAKE_DP_M_MAX 90
|
||||
#define IRONLAKE_DP_P_MIN 10
|
||||
#define IRONLAKE_DP_P_MAX 20
|
||||
#define IRONLAKE_DP_P2_FAST 10
|
||||
#define IRONLAKE_DP_P2_SLOW 10
|
||||
#define IRONLAKE_DP_P2_LIMIT 0
|
||||
#define IRONLAKE_DP_P1_MIN 1
|
||||
#define IRONLAKE_DP_P1_MAX 2
|
||||
|
||||
static bool
|
||||
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
|
@ -474,33 +527,78 @@ static const intel_limit_t intel_limits_pineview_lvds = {
|
|||
.find_pll = intel_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_ironlake_sdvo = {
|
||||
static const intel_limit_t intel_limits_ironlake_dac = {
|
||||
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
|
||||
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
|
||||
.n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX },
|
||||
.m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX },
|
||||
.n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX },
|
||||
.m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX },
|
||||
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
|
||||
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
|
||||
.p = { .min = IRONLAKE_P_SDVO_DAC_MIN, .max = IRONLAKE_P_SDVO_DAC_MAX },
|
||||
.p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX },
|
||||
.p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX },
|
||||
.p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX },
|
||||
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
|
||||
.p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW,
|
||||
.p2_fast = IRONLAKE_P2_SDVO_DAC_FAST },
|
||||
.p2_slow = IRONLAKE_DAC_P2_SLOW,
|
||||
.p2_fast = IRONLAKE_DAC_P2_FAST },
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_ironlake_lvds = {
|
||||
static const intel_limit_t intel_limits_ironlake_single_lvds = {
|
||||
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
|
||||
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
|
||||
.n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX },
|
||||
.m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX },
|
||||
.n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX },
|
||||
.m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX },
|
||||
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
|
||||
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
|
||||
.p = { .min = IRONLAKE_P_LVDS_MIN, .max = IRONLAKE_P_LVDS_MAX },
|
||||
.p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX },
|
||||
.p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX },
|
||||
.p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX },
|
||||
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
|
||||
.p2_slow = IRONLAKE_P2_LVDS_SLOW,
|
||||
.p2_fast = IRONLAKE_P2_LVDS_FAST },
|
||||
.p2_slow = IRONLAKE_LVDS_S_P2_SLOW,
|
||||
.p2_fast = IRONLAKE_LVDS_S_P2_FAST },
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_ironlake_dual_lvds = {
|
||||
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
|
||||
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
|
||||
.n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX },
|
||||
.m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX },
|
||||
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
|
||||
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
|
||||
.p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX },
|
||||
.p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX },
|
||||
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
|
||||
.p2_slow = IRONLAKE_LVDS_D_P2_SLOW,
|
||||
.p2_fast = IRONLAKE_LVDS_D_P2_FAST },
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
|
||||
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
|
||||
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
|
||||
.n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX },
|
||||
.m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX },
|
||||
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
|
||||
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
|
||||
.p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX },
|
||||
.p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX },
|
||||
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
|
||||
.p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW,
|
||||
.p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST },
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
|
||||
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
|
||||
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
|
||||
.n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX },
|
||||
.m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX },
|
||||
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
|
||||
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
|
||||
.p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX },
|
||||
.p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX },
|
||||
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
|
||||
.p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW,
|
||||
.p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST },
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
|
@ -509,34 +607,53 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
|
|||
.max = IRONLAKE_DOT_MAX },
|
||||
.vco = { .min = IRONLAKE_VCO_MIN,
|
||||
.max = IRONLAKE_VCO_MAX},
|
||||
.n = { .min = IRONLAKE_N_MIN,
|
||||
.max = IRONLAKE_N_MAX },
|
||||
.m = { .min = IRONLAKE_M_MIN,
|
||||
.max = IRONLAKE_M_MAX },
|
||||
.n = { .min = IRONLAKE_DP_N_MIN,
|
||||
.max = IRONLAKE_DP_N_MAX },
|
||||
.m = { .min = IRONLAKE_DP_M_MIN,
|
||||
.max = IRONLAKE_DP_M_MAX },
|
||||
.m1 = { .min = IRONLAKE_M1_MIN,
|
||||
.max = IRONLAKE_M1_MAX },
|
||||
.m2 = { .min = IRONLAKE_M2_MIN,
|
||||
.max = IRONLAKE_M2_MAX },
|
||||
.p = { .min = IRONLAKE_P_DISPLAY_PORT_MIN,
|
||||
.max = IRONLAKE_P_DISPLAY_PORT_MAX },
|
||||
.p1 = { .min = IRONLAKE_P1_DISPLAY_PORT_MIN,
|
||||
.max = IRONLAKE_P1_DISPLAY_PORT_MAX},
|
||||
.p2 = { .dot_limit = IRONLAKE_P2_DISPLAY_PORT_LIMIT,
|
||||
.p2_slow = IRONLAKE_P2_DISPLAY_PORT_SLOW,
|
||||
.p2_fast = IRONLAKE_P2_DISPLAY_PORT_FAST },
|
||||
.p = { .min = IRONLAKE_DP_P_MIN,
|
||||
.max = IRONLAKE_DP_P_MAX },
|
||||
.p1 = { .min = IRONLAKE_DP_P1_MIN,
|
||||
.max = IRONLAKE_DP_P1_MAX},
|
||||
.p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT,
|
||||
.p2_slow = IRONLAKE_DP_P2_SLOW,
|
||||
.p2_fast = IRONLAKE_DP_P2_FAST },
|
||||
.find_pll = intel_find_pll_ironlake_dp,
|
||||
};
|
||||
|
||||
static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
const intel_limit_t *limit;
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
|
||||
limit = &intel_limits_ironlake_lvds;
|
||||
else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
|
||||
int refclk = 120;
|
||||
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
|
||||
if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100)
|
||||
refclk = 100;
|
||||
|
||||
if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
|
||||
LVDS_CLKB_POWER_UP) {
|
||||
/* LVDS dual channel */
|
||||
if (refclk == 100)
|
||||
limit = &intel_limits_ironlake_dual_lvds_100m;
|
||||
else
|
||||
limit = &intel_limits_ironlake_dual_lvds;
|
||||
} else {
|
||||
if (refclk == 100)
|
||||
limit = &intel_limits_ironlake_single_lvds_100m;
|
||||
else
|
||||
limit = &intel_limits_ironlake_single_lvds;
|
||||
}
|
||||
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
|
||||
HAS_eDP)
|
||||
limit = &intel_limits_ironlake_display_port;
|
||||
else
|
||||
limit = &intel_limits_ironlake_sdvo;
|
||||
limit = &intel_limits_ironlake_dac;
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
@ -914,6 +1031,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
|||
|
||||
/* enable it... */
|
||||
fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
|
||||
if (IS_I945GM(dev))
|
||||
fbc_ctl |= FBC_C3_IDLE; /* 945 needs special SR handling */
|
||||
fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
|
||||
fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
|
||||
if (obj_priv->tiling_mode != I915_TILING_NONE)
|
||||
|
@ -3962,7 +4081,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
|
|||
struct intel_unpin_work {
|
||||
struct work_struct work;
|
||||
struct drm_device *dev;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_gem_object *old_fb_obj;
|
||||
struct drm_gem_object *pending_flip_obj;
|
||||
struct drm_pending_vblank_event *event;
|
||||
int pending;
|
||||
};
|
||||
|
@ -3973,8 +4093,9 @@ static void intel_unpin_work_fn(struct work_struct *__work)
|
|||
container_of(__work, struct intel_unpin_work, work);
|
||||
|
||||
mutex_lock(&work->dev->struct_mutex);
|
||||
i915_gem_object_unpin(work->obj);
|
||||
drm_gem_object_unreference(work->obj);
|
||||
i915_gem_object_unpin(work->old_fb_obj);
|
||||
drm_gem_object_unreference(work->pending_flip_obj);
|
||||
drm_gem_object_unreference(work->old_fb_obj);
|
||||
mutex_unlock(&work->dev->struct_mutex);
|
||||
kfree(work);
|
||||
}
|
||||
|
@ -3998,7 +4119,7 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
|
|||
work = intel_crtc->unpin_work;
|
||||
if (work == NULL || !work->pending) {
|
||||
if (work && !work->pending) {
|
||||
obj_priv = work->obj->driver_private;
|
||||
obj_priv = work->pending_flip_obj->driver_private;
|
||||
DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n",
|
||||
obj_priv,
|
||||
atomic_read(&obj_priv->pending_flip));
|
||||
|
@ -4023,7 +4144,7 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
|
|||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
obj_priv = work->obj->driver_private;
|
||||
obj_priv = work->pending_flip_obj->driver_private;
|
||||
|
||||
/* Initial scanout buffer will have a 0 pending flip count */
|
||||
if ((atomic_read(&obj_priv->pending_flip) == 0) ||
|
||||
|
@ -4060,7 +4181,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_unpin_work *work;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
|
||||
int ret, pipesrc;
|
||||
RING_LOCALS;
|
||||
|
||||
work = kzalloc(sizeof *work, GFP_KERNEL);
|
||||
|
@ -4072,7 +4194,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
work->event = event;
|
||||
work->dev = crtc->dev;
|
||||
intel_fb = to_intel_framebuffer(crtc->fb);
|
||||
work->obj = intel_fb->obj;
|
||||
work->old_fb_obj = intel_fb->obj;
|
||||
INIT_WORK(&work->work, intel_unpin_work_fn);
|
||||
|
||||
/* We borrow the event spin lock for protecting unpin_work */
|
||||
|
@ -4100,14 +4222,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Reference the old fb object for the scheduled work. */
|
||||
drm_gem_object_reference(work->obj);
|
||||
/* Reference the objects for the scheduled work. */
|
||||
drm_gem_object_reference(work->old_fb_obj);
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
crtc->fb = fb;
|
||||
i915_gem_object_flush_write_domain(obj);
|
||||
drm_vblank_get(dev, intel_crtc->pipe);
|
||||
obj_priv = obj->driver_private;
|
||||
atomic_inc(&obj_priv->pending_flip);
|
||||
work->pending_flip_obj = obj;
|
||||
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(MI_DISPLAY_FLIP |
|
||||
|
@ -4115,7 +4239,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
OUT_RING(fb->pitch);
|
||||
if (IS_I965G(dev)) {
|
||||
OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
|
||||
OUT_RING((fb->width << 16) | fb->height);
|
||||
pipesrc = I915_READ(pipesrc_reg);
|
||||
OUT_RING(pipesrc & 0x0fff0fff);
|
||||
} else {
|
||||
OUT_RING(obj_priv->gtt_offset);
|
||||
OUT_RING(MI_NOOP);
|
||||
|
|
|
@ -148,7 +148,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
ret = i915_gem_object_pin(fbo, PAGE_SIZE);
|
||||
ret = i915_gem_object_pin(fbo, 64*1024);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin fb: %d\n", ret);
|
||||
goto out_unref;
|
||||
|
|
Loading…
Reference in a new issue